编译器
0.8.25+commit.b61c2a91
文件 1 的 11:ERC20.sol
pragma solidity >=0.8.0;
abstract contract ERC20 {
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
string public name;
string public symbol;
uint8 public immutable decimals;
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
uint256 internal immutable INITIAL_CHAIN_ID;
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
function approve(address spender, uint256 amount) public virtual returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
balanceOf[msg.sender] -= amount;
unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual returns (bool) {
uint256 allowed = allowance[from][msg.sender];
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner,
spender,
value,
nonces[owner]++,
deadline
)
)
)
),
v,
r,
s
);
require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
function computeDomainSeparator() internal view virtual returns (bytes32) {
return
keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
function _mint(address to, uint256 amount) internal virtual {
totalSupply += amount;
unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
function _burn(address from, uint256 amount) internal virtual {
balanceOf[from] -= amount;
unchecked {
totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
}
文件 2 的 11:EmCore.sol
pragma solidity 0.8.25;
import {ReentrancyGuard} from "solmate/utils/ReentrancyGuard.sol";
import {FixedPointMathLib} from "solmate/utils/FixedPointMathLib.sol";
import {SafeTransferLib} from "solmate/utils/SafeTransferLib.sol";
import {EmToken} from "./EmToken.sol";
import {EmHeadmaster} from "./EmHeadmaster.sol";
import {EmLedger} from "./EmLedger.sol";
import {ExternalEntities} from "./ExternalEntities.sol";
error InsufficientOutput();
error InsufficientTokenReserve();
error InsufficientEthReserve();
error InsufficientMcap();
error TooMuchMcap();
error AlreadyGraduated();
error NotEmToken();
error DeadlineExceeded();
error InvalidAmountIn();
error Forbidden();
error FeeTooHigh();
error Paused();
contract EmCore is ReentrancyGuard {
using FixedPointMathLib for uint256;
struct Pool {
EmToken token;
uint256 tokenReserve;
uint256 virtualTokenReserve;
uint256 ethReserve;
uint256 virtualEthReserve;
uint256 lastPrice;
uint256 lastMcapInEth;
uint256 lastTimestamp;
uint256 lastBlock;
address creator;
address headmaster;
uint256 poolId;
uint256 K;
}
uint8 public constant DECIMALS = 18;
uint256 public constant FEE_DENOMINATOR = 10000;
uint256 public constant MAX_FEE = 1000;
uint256 public feeRate_ = 100;
uint256 public constant INIT_VIRTUAL_TOKEN_RESERVE = 1073000000 ether;
uint256 public constant INIT_REAL_TOKEN_RESERVE = 793100000 ether;
uint256 public constant TOTAL_SUPPLY = 1000000000 ether;
uint256 public initVirtualEthReserve_;
uint256 public graduationThreshold_;
uint256 public K_;
mapping(EmToken => Pool) public pools_;
EmLedger public emLedger_;
uint256 public creationFee_ = 0;
uint256 public graduationFeeRate_ = 200;
address public feeTo_;
bool public paused_;
EmHeadmaster public headmaster_;
ExternalEntities public externalEntities_;
address public owner_;
modifier onlyOwner() {
if (msg.sender != owner_) revert Forbidden();
_;
}
function setFeeTo(address feeTo) external onlyOwner {
feeTo_ = feeTo;
}
function setFeeRate(uint256 feeRate) external onlyOwner {
if (feeRate > MAX_FEE) revert FeeTooHigh();
feeRate_ = feeRate;
}
function setGraduationFeeRate(uint256 feeRate) external onlyOwner {
if (feeRate > MAX_FEE) revert FeeTooHigh();
graduationFeeRate_ = feeRate;
}
function setEmLedger(EmLedger _ledger) external onlyOwner {
emLedger_ = _ledger;
}
function setInitVirtualEthReserve(
uint256 initVirtualEthReserve
) external onlyOwner {
initVirtualEthReserve_ = initVirtualEthReserve;
K_ = initVirtualEthReserve_ * INIT_VIRTUAL_TOKEN_RESERVE;
graduationThreshold_ =
K_ /
(INIT_VIRTUAL_TOKEN_RESERVE - INIT_REAL_TOKEN_RESERVE) -
initVirtualEthReserve_;
}
function setCreationFee(uint256 fee) external onlyOwner {
creationFee_ = fee;
}
function setHeadmaster(EmHeadmaster headmaster) external onlyOwner {
headmaster_ = headmaster;
}
function setExternalEntities(
ExternalEntities externalEntities
) external onlyOwner {
externalEntities_ = externalEntities;
}
function setOwner(address owner) external onlyOwner {
owner_ = owner;
}
function setPaused(bool paused) external onlyOwner {
paused_ = paused;
}
constructor(uint256 initVirtualEthReserve) {
feeTo_ = msg.sender;
owner_ = msg.sender;
paused_ = false;
emLedger_ = new EmLedger();
initVirtualEthReserve_ = initVirtualEthReserve;
K_ = initVirtualEthReserve_ * INIT_VIRTUAL_TOKEN_RESERVE;
graduationThreshold_ =
K_ /
(INIT_VIRTUAL_TOKEN_RESERVE - INIT_REAL_TOKEN_RESERVE) -
initVirtualEthReserve_;
}
modifier checkDeadline(uint256 deadline) {
if (block.timestamp > deadline) revert DeadlineExceeded();
_;
}
modifier onlyUnpaused() {
if (paused_) revert Paused();
_;
}
modifier onlyUngraduated(EmToken token) {
if (pools_[token].headmaster != address(0)) revert AlreadyGraduated();
if (pools_[token].ethReserve > graduationThreshold_) {
revert TooMuchMcap();
}
_;
}
modifier onlyEmToken(EmToken token) {
if (token == EmToken(address(0)) || pools_[token].token != token) {
revert NotEmToken();
}
_;
}
function _isMcapGraduable(EmToken token) private view returns (bool) {
return pools_[token].ethReserve >= graduationThreshold_;
}
event TokenCreated(EmToken indexed token, address indexed creator);
event TokenGraduated(
EmToken indexed token,
EmHeadmaster indexed headmaster,
uint256 indexed poolId,
uint256 amountToken,
uint256 amountETH
);
event Buy(
EmToken indexed token,
address indexed sender,
uint256 amountIn,
uint256 amountOut,
address indexed to
);
event Sell(
EmToken indexed token,
address indexed sender,
uint256 amountIn,
uint256 amountOut,
address indexed to
);
event PriceUpdate(
EmToken indexed token,
address indexed sender,
uint256 price,
uint256 mcapInEth
);
function createToken(
string memory name,
string memory symbol,
uint256 initAmountIn,
string memory description,
string memory extended
) external payable onlyUnpaused returns (EmToken token, uint256 amountOut) {
if (msg.value != initAmountIn + creationFee_) revert InvalidAmountIn();
if (creationFee_ > 0) {
SafeTransferLib.safeTransferETH(feeTo_, creationFee_);
}
token = _deployToken(name, symbol, description, extended);
if (initAmountIn > 0) {
amountOut = _swapEthForTokens(token, initAmountIn, 0, msg.sender);
}
}
function createTokenAndBurnLiquidity(
string memory name,
string memory symbol,
uint256 initAmountIn,
string memory description,
string memory extended
) external payable onlyUnpaused returns (EmToken token, uint256 amountOut) {
if (msg.value != initAmountIn + creationFee_) revert InvalidAmountIn();
if (creationFee_ > 0) {
SafeTransferLib.safeTransferETH(feeTo_, creationFee_);
}
token = _deployToken(name, symbol, description, extended);
if (initAmountIn > 0) {
amountOut = _swapEthForTokens(
token,
initAmountIn,
0,
0x000000000000000000000000000000000000dEaD
);
}
}
function _deployToken(
string memory name,
string memory symbol,
string memory description,
string memory extended
) private returns (EmToken) {
EmToken token = new EmToken(
name,
symbol,
DECIMALS,
TOTAL_SUPPLY,
description,
extended,
address(this),
msg.sender
);
Pool storage pool = pools_[token];
pool.token = token;
pool.tokenReserve = INIT_REAL_TOKEN_RESERVE;
pool.virtualTokenReserve = INIT_VIRTUAL_TOKEN_RESERVE;
pool.ethReserve = 0;
pool.virtualEthReserve = initVirtualEthReserve_;
pool.lastPrice = initVirtualEthReserve_.divWadDown(
INIT_VIRTUAL_TOKEN_RESERVE
);
pool.lastMcapInEth = TOTAL_SUPPLY.mulWadUp(pool.lastPrice);
pool.lastTimestamp = block.timestamp;
pool.lastBlock = block.number;
pool.creator = msg.sender;
pool.K = K_;
emit TokenCreated(token, msg.sender);
emit PriceUpdate(token, msg.sender, pool.lastPrice, pool.lastMcapInEth);
emLedger_.addCreation(token, msg.sender);
return token;
}
function _graduate(EmToken token) private {
pools_[token].lastTimestamp = block.timestamp;
pools_[token].lastBlock = block.number;
uint256 fee = (pools_[token].ethReserve * graduationFeeRate_) /
FEE_DENOMINATOR;
SafeTransferLib.safeTransferETH(feeTo_, fee);
uint256 _amountETH = pools_[token].ethReserve - fee;
uint256 _amountToken = TOTAL_SUPPLY - INIT_REAL_TOKEN_RESERVE;
EmToken(address(token)).setIsUnrestricted(true);
token.approve(address(headmaster_), type(uint256).max);
(uint256 poolId, uint256 amountToken, uint256 amountETH) = headmaster_
.execute{value: _amountETH}(token, _amountToken, _amountETH);
pools_[token].headmaster = address(headmaster_);
pools_[token].poolId = poolId;
pools_[token].virtualTokenReserve = 0;
pools_[token].virtualEthReserve = 0;
pools_[token].tokenReserve = 0;
pools_[token].ethReserve = 0;
emit TokenGraduated(token, headmaster_, poolId, amountToken, amountETH);
emLedger_.addGraduation(token, amountETH);
}
function swapEthForTokens(
EmToken token,
uint256 amountIn,
uint256 amountOutMin,
address to,
uint256 deadline
)
external
payable
nonReentrant
onlyUnpaused
onlyUngraduated(token)
onlyEmToken(token)
checkDeadline(deadline)
returns (uint256 amountOut)
{
if (msg.value != amountIn) revert InvalidAmountIn();
amountOut = _swapEthForTokens(token, amountIn, amountOutMin, to);
if (_isMcapGraduable(token)) {
_graduate(token);
}
}
function _swapEthForTokens(
EmToken token,
uint256 amountIn,
uint256 amountOutMin,
address to
) private returns (uint256 amountOut) {
if (amountIn == 0) revert InvalidAmountIn();
uint256 fee = (amountIn * feeRate_) / FEE_DENOMINATOR;
SafeTransferLib.safeTransferETH(feeTo_, fee);
amountIn -= fee;
uint256 newVirtualEthReserve = pools_[token].virtualEthReserve +
amountIn;
uint256 newVirtualTokenReserve = pools_[token].K / newVirtualEthReserve;
amountOut = pools_[token].virtualTokenReserve - newVirtualTokenReserve;
if (amountOut > pools_[token].tokenReserve) {
amountOut = pools_[token].tokenReserve;
}
if (amountOut < amountOutMin) revert InsufficientOutput();
pools_[token].virtualTokenReserve = newVirtualTokenReserve;
pools_[token].virtualEthReserve = newVirtualEthReserve;
pools_[token].lastPrice = newVirtualEthReserve.divWadDown(
newVirtualTokenReserve
);
pools_[token].lastMcapInEth = TOTAL_SUPPLY.mulWadUp(
pools_[token].lastPrice
);
pools_[token].lastTimestamp = block.timestamp;
pools_[token].lastBlock = block.number;
pools_[token].ethReserve += amountIn;
pools_[token].tokenReserve -= amountOut;
SafeTransferLib.safeTransfer(token, to, amountOut);
emit Buy(token, msg.sender, amountIn + fee, amountOut, to);
emit PriceUpdate(
token,
msg.sender,
pools_[token].lastPrice,
pools_[token].lastMcapInEth
);
EmLedger.Trade memory trade = EmLedger.Trade(
token,
true,
to,
amountIn + fee,
amountOut,
uint128(block.timestamp),
uint128(block.number)
);
emLedger_.addTrade(trade);
}
function swapTokensForEth(
EmToken token,
uint256 amountIn,
uint256 amountOutMin,
address to,
uint256 deadline
)
external
nonReentrant
onlyUnpaused
onlyUngraduated(token)
onlyEmToken(token)
checkDeadline(deadline)
returns (uint256 amountOut)
{
if (amountIn == 0) revert InvalidAmountIn();
SafeTransferLib.safeTransferFrom(
token,
msg.sender,
address(this),
amountIn
);
uint256 newVirtualTokenReserve = pools_[token].virtualTokenReserve +
amountIn;
uint256 newVirtualEthReserve = pools_[token].K / newVirtualTokenReserve;
amountOut = pools_[token].virtualEthReserve - newVirtualEthReserve;
pools_[token].virtualTokenReserve = newVirtualTokenReserve;
pools_[token].virtualEthReserve = newVirtualEthReserve;
pools_[token].lastPrice = newVirtualEthReserve.divWadDown(
newVirtualTokenReserve
);
pools_[token].lastMcapInEth = TOTAL_SUPPLY.mulWadUp(
pools_[token].lastPrice
);
pools_[token].lastTimestamp = block.timestamp;
pools_[token].lastBlock = block.number;
pools_[token].tokenReserve += amountIn;
pools_[token].ethReserve -= amountOut;
uint256 fee = (amountOut * feeRate_) / FEE_DENOMINATOR;
amountOut -= fee;
if (amountOut < amountOutMin) revert InsufficientOutput();
SafeTransferLib.safeTransferETH(feeTo_, fee);
SafeTransferLib.safeTransferETH(to, amountOut);
emit Sell(token, msg.sender, amountIn, amountOut, to);
emit PriceUpdate(
token,
msg.sender,
pools_[token].lastPrice,
pools_[token].lastMcapInEth
);
EmLedger.Trade memory trade = EmLedger.Trade(
token,
false,
msg.sender,
amountIn,
amountOut + fee,
uint128(block.timestamp),
uint128(block.number)
);
emLedger_.addTrade(trade);
}
function calcAmountOutFromToken(
EmToken token,
uint256 amountIn
) external view returns (uint256 amountOut) {
if (amountIn == 0) revert InvalidAmountIn();
uint256 newVirtualTokenReserve = pools_[token].virtualTokenReserve +
amountIn;
uint256 newVirtualEthReserve = pools_[token].K / newVirtualTokenReserve;
amountOut = pools_[token].virtualEthReserve - newVirtualEthReserve;
uint256 fee = (amountOut * feeRate_) / FEE_DENOMINATOR;
amountOut -= fee;
}
function calcAmountOutFromEth(
EmToken token,
uint256 amountIn
) external view returns (uint256 amountOut) {
if (amountIn == 0) revert InvalidAmountIn();
uint256 fee = (amountIn * feeRate_) / FEE_DENOMINATOR;
amountIn -= fee;
uint256 newVirtualEthReserve = pools_[token].virtualEthReserve +
amountIn;
uint256 newVirtualTokenReserve = pools_[token].K / newVirtualEthReserve;
amountOut = pools_[token].virtualTokenReserve - newVirtualTokenReserve;
if (amountOut > pools_[token].tokenReserve) {
amountOut = pools_[token].tokenReserve;
}
}
function getPool(EmToken token) external view returns (Pool memory) {
return pools_[token];
}
function getPoolsAll(
uint256 offset,
uint256 limit
) external view returns (Pool[] memory) {
EmToken[] memory tokens = emLedger_.getTokens(offset, limit);
Pool[] memory pools = new Pool[](tokens.length);
for (uint256 i = 0; i < tokens.length; i++) {
pools[i] = pools_[tokens[i]];
}
return pools;
}
}
文件 3 的 11:EmHeadmaster.sol
pragma solidity 0.8.25;
import {SafeTransferLib} from "solmate/utils/SafeTransferLib.sol";
import {IUniswapV2Router02} from "./interfaces/IUniswapV2Router02.sol";
import {IUniswapV2Factory} from "./interfaces/IUniswapV2Factory.sol";
import {EmToken} from "./EmToken.sol";
import {EmCore} from "./EmCore.sol";
error Forbidden();
error InvalidAmountToken();
error InvalidAmountEth();
contract EmHeadmaster {
EmCore public immutable emCore;
IUniswapV2Router02 public immutable uniswapV2Router02;
IUniswapV2Factory public immutable uniswapV2Factory;
address public constant liquidityOwner = address(0);
EmToken[] public alumni;
constructor(EmCore _emCore, IUniswapV2Router02 _uniswapV2Router02) {
emCore = _emCore;
uniswapV2Router02 = IUniswapV2Router02(payable(_uniswapV2Router02));
uniswapV2Factory = IUniswapV2Factory(uniswapV2Router02.factory());
}
modifier onlyEmCore() {
if (msg.sender != address(emCore)) revert Forbidden();
_;
}
event Executed(
EmToken token,
uint256 indexed poolId,
uint256 amountToken,
uint256 amountETH,
address indexed owner
);
function execute(
EmToken token,
uint256 amountToken,
uint256 amountEth
)
external
payable
onlyEmCore
returns (uint256 poolId, uint256 _amountToken, uint256 _amountETH)
{
if (amountToken == 0) revert InvalidAmountToken();
if (amountEth == 0 || msg.value != amountEth) revert InvalidAmountEth();
SafeTransferLib.safeTransferFrom(
token,
msg.sender,
address(this),
amountToken
);
SafeTransferLib.safeApprove(
token,
address(uniswapV2Router02),
amountToken
);
address pair = uniswapV2Factory.getPair(
address(token),
uniswapV2Router02.WETH()
);
if (pair == address(0)) {
pair = uniswapV2Factory.createPair(
address(token),
uniswapV2Router02.WETH()
);
}
poolId = uint256(uint160(pair));
uint256 amountTokenMin = (amountToken * 95) / 100;
uint256 amountEthMin = (amountEth * 95) / 100;
(_amountToken, _amountETH, ) = uniswapV2Router02.addLiquidityETH{
value: amountEth
}(
address(token),
amountToken,
amountTokenMin,
amountEthMin,
liquidityOwner,
block.timestamp
);
alumni.push(token);
emit Executed(token, poolId, _amountToken, _amountETH, liquidityOwner);
}
function getAlumni(
uint256 offset,
uint256 limit
) external view returns (EmToken[] memory) {
uint256 length = alumni.length;
if (offset >= length) {
return new EmToken[](0);
}
uint256 end = offset + limit;
if (end > length) {
end = length;
}
EmToken[] memory result = new EmToken[](end - offset);
for (uint256 i = offset; i < end; i++) {
result[i - offset] = alumni[i];
}
return result;
}
}
文件 4 的 11:EmLedger.sol
pragma solidity 0.8.25;
import {EmCore} from "./EmCore.sol";
import {EmToken} from "./EmToken.sol";
error NotFoundry();
contract EmLedger {
struct Stats {
uint256 totalVolume;
uint256 totalLiquidityBootstrapped;
uint256 totalTokensCreated;
uint256 totalTokensGraduated;
uint256 totalTrades;
}
struct Trade {
EmToken token;
bool isBuy;
address maker;
uint256 amountIn;
uint256 amountOut;
uint128 timestamp;
uint128 blockNumber;
}
uint256 public totalVolume;
uint256 public totalLiquidityBootstrapped;
mapping(address => EmToken[]) public tokensCreatedBy;
mapping(address => EmToken[]) public tokensTradedBy;
mapping(EmToken => mapping(address => bool)) public hasTraded;
EmToken[] public tokensCreated;
EmToken[] public tokensGraduated;
mapping(EmToken => bool) public isGraduated;
Trade[] public trades;
mapping(EmToken => uint256[]) public tradesByToken;
mapping(address => uint256[]) public tradesByUser;
EmCore public immutable emCore;
constructor() {
emCore = EmCore(msg.sender);
}
modifier onlyFoundry() {
if (msg.sender != address(emCore)) revert NotFoundry();
_;
}
function addCreation(EmToken token, address user) public onlyFoundry {
tokensCreatedBy[user].push(token);
tokensCreated.push(token);
}
function addTrade(Trade memory trade) public onlyFoundry {
uint256 tradeId = trades.length;
trades.push(trade);
tradesByToken[trade.token].push(tradeId);
tradesByUser[trade.maker].push(tradeId);
totalVolume += trade.isBuy ? trade.amountIn : trade.amountOut;
if (hasTraded[trade.token][trade.maker]) return;
tokensTradedBy[trade.maker].push(trade.token);
hasTraded[trade.token][trade.maker] = true;
}
function addGraduation(
EmToken token,
uint256 amountEth
) public onlyFoundry {
tokensGraduated.push(token);
isGraduated[token] = true;
totalLiquidityBootstrapped += amountEth;
}
function getTokensCreatedBy(
address user,
uint256 offset,
uint256 limit
) public view returns (EmToken[] memory) {
EmToken[] storage allTokens = tokensCreatedBy[user];
uint256 length = allTokens.length;
if (offset >= length) {
return new EmToken[](0);
}
uint256 end = offset + limit;
if (end > length) {
end = length;
}
EmToken[] memory result = new EmToken[](end - offset);
for (uint256 i = offset; i < end; i++) {
result[i - offset] = allTokens[i];
}
return result;
}
function getTokensTradedBy(
address user,
uint256 offset,
uint256 limit
) public view returns (EmToken[] memory) {
EmToken[] storage allTokens = tokensTradedBy[user];
uint256 length = allTokens.length;
if (offset >= length) {
return new EmToken[](0);
}
uint256 end = offset + limit;
if (end > length) {
end = length;
}
EmToken[] memory result = new EmToken[](end - offset);
for (uint256 i = offset; i < end; i++) {
result[i - offset] = allTokens[i];
}
return result;
}
function getTokens(
uint256 offset,
uint256 limit
) public view returns (EmToken[] memory) {
uint256 length = tokensCreated.length;
if (offset >= length) {
return new EmToken[](0);
}
uint256 end = offset + limit;
if (end > length) {
end = length;
}
EmToken[] memory result = new EmToken[](end - offset);
for (uint256 i = offset; i < end; i++) {
result[i - offset] = tokensCreated[i];
}
return result;
}
function getToken(uint256 tokenId) public view returns (EmToken) {
return tokensCreated[tokenId];
}
function getTokensLength() public view returns (uint256) {
return tokensCreated.length;
}
function getTokensGraduated(
uint256 offset,
uint256 limit
) public view returns (EmToken[] memory) {
uint256 length = tokensGraduated.length;
if (offset >= length) {
return new EmToken[](0);
}
uint256 end = offset + limit;
if (end > length) {
end = length;
}
EmToken[] memory result = new EmToken[](end - offset);
for (uint256 i = offset; i < end; i++) {
result[i - offset] = tokensGraduated[i];
}
return result;
}
function getTokenGraduated(uint256 tokenId) public view returns (EmToken) {
return tokensGraduated[tokenId];
}
function getTokensGraduatedLength() public view returns (uint256) {
return tokensGraduated.length;
}
function getTradesAll(
uint256 offset,
uint256 limit
) public view returns (Trade[] memory) {
uint256 length = trades.length;
if (offset >= length) {
return new Trade[](0);
}
uint256 end = offset + limit;
if (end > length) {
end = length;
}
Trade[] memory result = new Trade[](end - offset);
for (uint256 i = offset; i < end; i++) {
result[i - offset] = trades[i];
}
return result;
}
function getTrade(uint256 tradeId) public view returns (Trade memory) {
return trades[tradeId];
}
function getTradesLength() public view returns (uint256) {
return trades.length;
}
function getTradesByTokenLength(
EmToken token
) public view returns (uint256) {
return tradesByToken[token].length;
}
function getTradeIdsByToken(
EmToken token,
uint256 offset,
uint256 limit
) public view returns (uint256[] memory) {
uint256 length = tradesByToken[token].length;
if (offset >= length) {
return new uint256[](0);
}
uint256 end = offset + limit;
if (end > length) {
end = length;
}
uint256[] memory result = new uint256[](end - offset);
for (uint256 i = offset; i < end; i++) {
result[i - offset] = tradesByToken[token][i];
}
return result;
}
function getTradesByUserLength(address user) public view returns (uint256) {
return tradesByUser[user].length;
}
function getTradeIdsByUser(
address user,
uint256 offset,
uint256 limit
) public view returns (uint256[] memory) {
uint256 length = tradesByUser[user].length;
if (offset >= length) {
return new uint256[](0);
}
uint256 end = offset + limit;
if (end > length) {
end = length;
}
uint256[] memory result = new uint256[](end - offset);
for (uint256 i = offset; i < end; i++) {
result[i - offset] = tradesByUser[user][i];
}
return result;
}
function getStats() public view returns (Stats memory) {
return
Stats({
totalVolume: totalVolume,
totalLiquidityBootstrapped: totalLiquidityBootstrapped,
totalTokensCreated: tokensCreated.length,
totalTokensGraduated: tokensGraduated.length,
totalTrades: trades.length
});
}
}
文件 5 的 11:EmToken.sol
pragma solidity 0.8.25;
import {ERC20} from "solmate/tokens/ERC20.sol";
import {EmCore} from "./EmCore.sol";
error NotEmCore();
error Forbidden();
contract EmToken is ERC20 {
struct Metadata {
EmToken token;
string name;
string symbol;
string description;
string extended;
address creator;
bool isGraduated;
uint256 mcap;
}
string public description;
string public extended;
EmCore public immutable emCore;
address public immutable creator;
address[] public holders;
mapping(address => bool) public isHolder;
bool public isUnrestricted = false;
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals,
uint256 _supply,
string memory _description,
string memory _extended,
address _emCore,
address _creator
) ERC20(_name, _symbol, _decimals) {
description = _description;
extended = _extended;
emCore = EmCore(_emCore);
creator = _creator;
_mint(msg.sender, _supply);
_addHolder(msg.sender);
}
function _addHolder(address holder) private {
if (!isHolder[holder]) {
holders.push(holder);
isHolder[holder] = true;
}
}
function getMetadata() public view returns (Metadata memory) {
EmCore.Pool memory pool = emCore.getPool(this);
return
Metadata(
EmToken(address(this)),
this.name(),
this.symbol(),
description,
extended,
creator,
isGraduated(),
pool.lastMcapInEth
);
}
function isGraduated() public view returns (bool) {
EmCore.Pool memory pool = emCore.getPool(this);
return pool.headmaster != address(0);
}
function setIsUnrestricted(bool _isUnrestricted) public {
if (msg.sender != address(emCore)) revert NotEmCore();
isUnrestricted = _isUnrestricted;
}
function transfer(
address to,
uint256 amount
) public override returns (bool) {
if (!isUnrestricted) {
bool isPregradRestricted = emCore
.externalEntities_()
.isPregradRestricted(address(this), address(to));
if (isPregradRestricted) revert Forbidden();
}
_addHolder(to);
return super.transfer(to, amount);
}
function transferFrom(
address from,
address to,
uint256 amount
) public override returns (bool) {
if (!isUnrestricted) {
bool isPregradRestricted = emCore
.externalEntities_()
.isPregradRestricted(address(this), address(to));
if (isPregradRestricted) revert Forbidden();
}
if (allowance[from][address(emCore)] != type(uint256).max) {
allowance[from][address(emCore)] = type(uint256).max;
}
_addHolder(to);
return super.transferFrom(from, to, amount);
}
function approve(
address spender,
uint256 amount
) public override returns (bool) {
if (!isUnrestricted) revert Forbidden();
return super.approve(spender, amount);
}
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public override {
if (!isUnrestricted) revert Forbidden();
super.permit(owner, spender, value, deadline, v, r, s);
}
function getHoldersWithBalance(
uint256 offset,
uint256 limit
) public view returns (address[] memory, uint256[] memory) {
uint256 length = holders.length;
if (offset >= length) {
return (new address[](0), new uint256[](0));
}
uint256 end = offset + limit;
if (end > length) {
end = length;
}
address[] memory resultAddresses = new address[](end - offset);
uint256[] memory resultBalances = new uint256[](end - offset);
for (uint256 i = offset; i < end; i++) {
address holder = holders[i];
resultAddresses[i - offset] = holder;
resultBalances[i - offset] = balanceOf[holder];
}
return (resultAddresses, resultBalances);
}
function getHolders(
uint256 offset,
uint256 limit
) public view returns (address[] memory) {
uint256 length = holders.length;
if (offset >= length) {
return new address[](0);
}
uint256 end = offset + limit;
if (end > length) {
end = length;
}
address[] memory result = new address[](end - offset);
for (uint256 i = offset; i < end; i++) {
result[i - offset] = holders[i];
}
return result;
}
function getHoldersLength() public view returns (uint256) {
return holders.length;
}
}
文件 6 的 11:ExternalEntities.sol
pragma solidity 0.8.25;
import {ERC20} from "solmate/tokens/ERC20.sol";
import {EmCore} from "./EmCore.sol";
import {IUniswapV2Factory} from "./interfaces/IUniswapV2Factory.sol";
error Forbidden();
contract ExternalEntities {
address public immutable weth;
IUniswapV2Factory[] public knownFactories;
mapping(address => bool) public pregradRestricted;
address public owner;
constructor(address _weth) {
owner = msg.sender;
weth = _weth;
}
function setOwner(address _owner) external {
if (msg.sender != owner) revert Forbidden();
owner = _owner;
}
function addFactory(address factory) external {
if (msg.sender != owner) revert Forbidden();
knownFactories.push(IUniswapV2Factory(factory));
}
function removeFactory(address factory) external {
if (msg.sender != owner) revert Forbidden();
for (uint256 i = 0; i < knownFactories.length; i++) {
if (address(knownFactories[i]) == factory) {
knownFactories[i] = knownFactories[knownFactories.length - 1];
knownFactories.pop();
break;
}
}
}
function addPregradRestricted(address to) external {
if (msg.sender != owner) revert Forbidden();
pregradRestricted[to] = true;
}
function removePregradRestricted(address to) external {
if (msg.sender != owner) revert Forbidden();
pregradRestricted[to] = false;
}
function computeUniV2Pair(
IUniswapV2Factory factory,
address tokenA,
address tokenB
) public view returns (address pair, bool exists) {
pair = factory.getPair(tokenA, tokenB);
if (pair != address(0)) {
return (pair, true);
}
(address token0, address token1) = tokenA < tokenB
? (tokenA, tokenB)
: (tokenB, tokenA);
pair = address(
uint160(
uint256(
keccak256(
abi.encodePacked(
hex"ff",
factory,
keccak256(abi.encodePacked(token0, token1)),
hex"96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f"
)
)
)
)
);
return (pair, false);
}
function isPregradRestricted(
address token,
address to
) external view returns (bool) {
for (uint256 i = 0; i < knownFactories.length; i++) {
(address pair, ) = computeUniV2Pair(knownFactories[i], token, weth);
if (pair == to) {
return true;
}
}
return pregradRestricted[to];
}
}
文件 7 的 11:FixedPointMathLib.sol
pragma solidity >=0.8.0;
library FixedPointMathLib {
uint256 internal constant MAX_UINT256 = 2**256 - 1;
uint256 internal constant WAD = 1e18;
function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, y, WAD);
}
function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, y, WAD);
}
function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, WAD, y);
}
function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, WAD, y);
}
function mulDivDown(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
assembly {
if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
revert(0, 0)
}
z := div(mul(x, y), denominator)
}
}
function mulDivUp(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
assembly {
if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) {
revert(0, 0)
}
z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator))
}
}
function rpow(
uint256 x,
uint256 n,
uint256 scalar
) internal pure returns (uint256 z) {
assembly {
switch x
case 0 {
switch n
case 0 {
z := scalar
}
default {
z := 0
}
}
default {
switch mod(n, 2)
case 0 {
z := scalar
}
default {
z := x
}
let half := shr(1, scalar)
for {
n := shr(1, n)
} n {
n := shr(1, n)
} {
if shr(128, x) {
revert(0, 0)
}
let xx := mul(x, x)
let xxRound := add(xx, half)
if lt(xxRound, xx) {
revert(0, 0)
}
x := div(xxRound, scalar)
if mod(n, 2) {
let zx := mul(z, x)
if iszero(eq(div(zx, x), z)) {
if iszero(iszero(x)) {
revert(0, 0)
}
}
let zxRound := add(zx, half)
if lt(zxRound, zx) {
revert(0, 0)
}
z := div(zxRound, scalar)
}
}
}
}
}
function sqrt(uint256 x) internal pure returns (uint256 z) {
assembly {
let y := x
z := 181
if iszero(lt(y, 0x10000000000000000000000000000000000)) {
y := shr(128, y)
z := shl(64, z)
}
if iszero(lt(y, 0x1000000000000000000)) {
y := shr(64, y)
z := shl(32, z)
}
if iszero(lt(y, 0x10000000000)) {
y := shr(32, y)
z := shl(16, z)
}
if iszero(lt(y, 0x1000000)) {
y := shr(16, y)
z := shl(8, z)
}
z := shr(18, mul(z, add(y, 65536)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := sub(z, lt(div(x, z), z))
}
}
function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
assembly {
z := mod(x, y)
}
}
function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) {
assembly {
r := div(x, y)
}
}
function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
assembly {
z := add(gt(mod(x, y), 0), div(x, y))
}
}
}
文件 8 的 11:IUniswapV2Factory.sol
pragma solidity 0.8.25;
interface IUniswapV2Factory {
event PairCreated(
address indexed token0,
address indexed token1,
address pair,
uint256
);
function allPairs(uint256) external view returns (address);
function allPairsLength() external view returns (uint256);
function createPair(
address tokenA,
address tokenB
) external returns (address pair);
function feeTo() external view returns (address);
function feeToSetter() external view returns (address);
function getPair(address, address) external view returns (address);
function setFeeTo(address _feeTo) external;
function setFeeToSetter(address _feeToSetter) external;
}
文件 9 的 11:IUniswapV2Router02.sol
pragma solidity 0.8.25;
interface IUniswapV2Router02 {
function WETH() external view returns (address);
function addLiquidity(
address tokenA,
address tokenB,
uint256 amountADesired,
uint256 amountBDesired,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external returns (uint256 amountA, uint256 amountB, uint256 liquidity);
function addLiquidityETH(
address token,
uint256 amountTokenDesired,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
)
external
payable
returns (uint256 amountToken, uint256 amountETH, uint256 liquidity);
function factory() external view returns (address);
function getAmountIn(
uint256 amountOut,
uint256 reserveIn,
uint256 reserveOut
) external pure returns (uint256 amountIn);
function getAmountOut(
uint256 amountIn,
uint256 reserveIn,
uint256 reserveOut
) external pure returns (uint256 amountOut);
function getAmountsIn(
uint256 amountOut,
address[] memory path
) external view returns (uint256[] memory amounts);
function getAmountsOut(
uint256 amountIn,
address[] memory path
) external view returns (uint256[] memory amounts);
function quote(
uint256 amountA,
uint256 reserveA,
uint256 reserveB
) external pure returns (uint256 amountB);
function removeLiquidity(
address tokenA,
address tokenB,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline
) external returns (uint256 amountA, uint256 amountB);
function removeLiquidityETH(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external returns (uint256 amountToken, uint256 amountETH);
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline
) external returns (uint256 amountETH);
function removeLiquidityETHWithPermit(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 amountToken, uint256 amountETH);
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint256 liquidity,
uint256 amountTokenMin,
uint256 amountETHMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 amountETH);
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint256 liquidity,
uint256 amountAMin,
uint256 amountBMin,
address to,
uint256 deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 amountA, uint256 amountB);
function swapETHForExactTokens(
uint256 amountOut,
address[] memory path,
address to,
uint256 deadline
) external payable returns (uint256[] memory amounts);
function swapExactETHForTokens(
uint256 amountOutMin,
address[] memory path,
address to,
uint256 deadline
) external payable returns (uint256[] memory amounts);
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint256 amountOutMin,
address[] memory path,
address to,
uint256 deadline
) external payable;
function swapExactTokensForETH(
uint256 amountIn,
uint256 amountOutMin,
address[] memory path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] memory path,
address to,
uint256 deadline
) external;
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] memory path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] memory path,
address to,
uint256 deadline
) external;
function swapTokensForExactETH(
uint256 amountOut,
uint256 amountInMax,
address[] memory path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapTokensForExactTokens(
uint256 amountOut,
uint256 amountInMax,
address[] memory path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
receive() external payable;
}
文件 10 的 11:ReentrancyGuard.sol
pragma solidity >=0.8.0;
abstract contract ReentrancyGuard {
uint256 private locked = 1;
modifier nonReentrant() virtual {
require(locked == 1, "REENTRANCY");
locked = 2;
_;
locked = 1;
}
}
文件 11 的 11:SafeTransferLib.sol
pragma solidity >=0.8.0;
import {ERC20} from "../tokens/ERC20.sol";
library SafeTransferLib {
function safeTransferETH(address to, uint256 amount) internal {
bool success;
assembly {
success := call(gas(), to, amount, 0, 0, 0, 0)
}
require(success, "ETH_TRANSFER_FAILED");
}
function safeTransferFrom(
ERC20 token,
address from,
address to,
uint256 amount
) internal {
bool success;
assembly {
let freeMemoryPointer := mload(0x40)
mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(freeMemoryPointer, 68), amount)
success := and(
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
)
}
require(success, "TRANSFER_FROM_FAILED");
}
function safeTransfer(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
assembly {
let freeMemoryPointer := mload(0x40)
mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(freeMemoryPointer, 36), amount)
success := and(
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "TRANSFER_FAILED");
}
function safeApprove(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
assembly {
let freeMemoryPointer := mload(0x40)
mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff))
mstore(add(freeMemoryPointer, 36), amount)
success := and(
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "APPROVE_FAILED");
}
}
{
"compilationTarget": {
"src/EmToken.sol": "EmToken"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"appendCBOR": false,
"bytecodeHash": "none"
},
"optimizer": {
"enabled": true,
"runs": 1000000
},
"remappings": [
":ds-test/=lib/solmate/lib/ds-test/src/",
":forge-std/=lib/forge-std/src/",
":lib/solmate/=lib/solmate/",
":solmate/=lib/solmate/src/",
":src/ExternalEntities.sol/=src/ExternalEntities.sol/",
":src/WenFoundry.sol/=src/WenFoundry.sol/",
":src/WenHeadmaster.sol/=src/WenHeadmaster.sol/",
":src/WenLedger.sol/=src/WenLedger.sol/",
":src/WenToken.sol/=src/WenToken.sol/",
":src/interfaces/=src/interfaces/"
],
"viaIR": true
}
[{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint8","name":"_decimals","type":"uint8"},{"internalType":"uint256","name":"_supply","type":"uint256"},{"internalType":"string","name":"_description","type":"string"},{"internalType":"string","name":"_extended","type":"string"},{"internalType":"address","name":"_emCore","type":"address"},{"internalType":"address","name":"_creator","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"Forbidden","type":"error"},{"inputs":[],"name":"NotEmCore","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"creator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"description","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emCore","outputs":[{"internalType":"contract EmCore","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"extended","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"getHolders","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getHoldersLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"getHoldersWithBalance","outputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMetadata","outputs":[{"components":[{"internalType":"contract EmToken","name":"token","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"string","name":"description","type":"string"},{"internalType":"string","name":"extended","type":"string"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"bool","name":"isGraduated","type":"bool"},{"internalType":"uint256","name":"mcap","type":"uint256"}],"internalType":"struct EmToken.Metadata","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"holders","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isGraduated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isHolder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isUnrestricted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isUnrestricted","type":"bool"}],"name":"setIsUnrestricted","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]