This contract's source code is verified! Compiler
0.8.25+commit.b61c2a91
File 1 of 9: 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);
}
}
File 2 of 9: 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;
}
}
File 3 of 9: 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;
}
}
File 4 of 9: 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 ;
}
}
File 5 of 9: 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];
}
}
File 6 of 9: 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 ;
}
File 7 of 9: 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 ;
}
File 8 of 9: 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 ;
}
}
File 9 of 9: 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"}]