Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"src/v2/Indexer.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "./Factory.sol";
contract Indexer {
event ERC20TokenCreated(
address indexed tokenAddress,
address indexed deployer,
uint256 timestamp
);
event SaltBruteforced(
bytes32 indexed usedSalt,
address indexed predictedToken
);
event FeesCollected(
uint256 indexed tokenId,
address indexed token,
uint256 tokenAmount,
uint256 ethAmount
);
event TokenPurchased(
address indexed buyer,
address indexed tokenOut,
uint256 ethSpent,
uint256 tokensReceived
);
event Buy(
address indexed buyer,
address indexed pool,
address indexed token,
uint256 amountTokens,
uint160 sqrtPriceX96,
uint256 priceX96,
uint256 ethAmount,
uint256 totalFeesETH,
uint256 totalFeesToken
);
event Sell(
address indexed seller,
address indexed pool,
address indexed token,
uint256 amountTokens,
uint160 sqrtPriceX96,
uint256 priceX96,
uint256 ethAmount,
uint256 totalFeesETH,
uint256 totalFeesToken
);
event BuybackExecuted(
address indexed targetToken,
uint256 wethSpent,
uint256 tokensBurned
);
error NotAuthorized();
mapping(address => bool) public authorizedAddresses;
address public factory;
constructor() {
authorizedAddresses[msg.sender] = true;
}
modifier onlyAuthorized() {
if (!authorizedAddresses[msg.sender]) revert NotAuthorized();
_;
}
function setFactory(address _factory) external onlyAuthorized() {
require(_factory != address(0), "Factory address is zero");
factory = _factory;
authorizedAddresses[_factory] = true;
}
function authorizeAddress(address _address) external onlyAuthorized {
authorizedAddresses[_address] = true;
}
function revokeAddress(address _address) external onlyAuthorized {
authorizedAddresses[_address] = false;
}
function emitERC20TokenCreated(
address tokenAddress,
address deployer
) external onlyAuthorized {
emit ERC20TokenCreated(tokenAddress, deployer, block.timestamp);
}
function emitSaltBruteforced(
bytes32 usedSalt,
address predictedToken
) external onlyAuthorized {
emit SaltBruteforced(usedSalt, predictedToken);
}
function emitFeesCollected(
uint256 tokenId,
address token,
uint256 tokenAmount,
uint256 ethAmount
) external onlyAuthorized {
emit FeesCollected(tokenId, token, tokenAmount, ethAmount);
}
function emitTokenPurchased(
address buyer,
address tokenOut,
uint256 ethSpent,
uint256 tokensReceived
) external onlyAuthorized {
emit TokenPurchased(buyer, tokenOut, ethSpent, tokensReceived);
}
function emitBuy(
address buyer,
address pool,
address token,
uint256 amountTokens,
uint160 sqrtPriceX96,
uint256 priceX96,
uint256 ethAmount,
uint256 totalFeesETH,
uint256 totalFeesToken
) external onlyAuthorized {
emit Buy(
buyer,
pool,
token,
amountTokens,
sqrtPriceX96,
priceX96,
ethAmount,
totalFeesETH,
totalFeesToken
);
}
function emitSell(
address seller,
address pool,
address token,
uint256 amountTokens,
uint160 sqrtPriceX96,
uint256 priceX96,
uint256 ethAmount,
uint256 totalFeesETH,
uint256 totalFeesToken
) external onlyAuthorized {
emit Sell(
seller,
pool,
token,
amountTokens,
sqrtPriceX96,
priceX96,
ethAmount,
totalFeesETH,
totalFeesToken
);
}
function emitBuybackExecuted(
address targetToken,
uint256 wethSpent,
uint256 tokensBurned
) external onlyAuthorized {
emit BuybackExecuted(targetToken, wethSpent, tokensBurned);
}
}
"
},
"src/v2/Factory.sol": {
"content": "
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import './Indexer.sol';
import './FactoryConveyor.sol' ;
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
contract Factory is ReentrancyGuard {
struct TokenInfo {
address tokenAddress;
string name;
string symbol;
address deployer;
uint256 time;
string metadata;
uint256 marketCapInETH;
uint256 nftId;
uint256 totalFeesGenerated;
}
IIndexer public indexer;
mapping(uint256 => TokenInfo) public deployedTokens;
mapping(address => TokenInfo) public tokenInfoByAddress;
uint256 public tokenCount;
uint256 public ethFeeGenerated;
address public platformController;
bool public deployCoinEnabled;
uint256 private itemsPerPage = 500;
mapping(address => address[]) public deployerTokens;
mapping(address => uint256) public tokenFeesGenerated;
mapping(address => uint256) public tokenFeesClaimed;
mapping(address => uint256) public tokenToNFTId;
mapping(address => address) public tokenToPool;
mapping(address => address) public tokenCreators;
struct LiquidityConfig {
uint160 sqrtPriceX96;
int24 tickLower;
int24 tickUpper;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 virtualAmount;
uint256 penaltyMultiplier;
}
mapping(uint256 => LiquidityConfig) public liquidityConfigs;
uint256 public liquidityConfigCount;
address public constant POSITION_MANAGER = UNISWAP_V3_POSITION_MANAGER;
address public constant WETH = WETH_ADDRESS;
address public constant SWAP_ROUTER = UNISWAP_V3_SWAP_ROUTER;
address public FACTORY = UNISWAP_V3_FACTORY;
uint24 private constant FEE_TIER = FEE_TIER_10000;
address public buybackPool;
address public devAddress;
address public buybackToken;
FactoryConveyor public conveyor;
constructor(address _indexer, address _buybackPool, address _devAddress) {
platformController = tx.origin;
indexer = IIndexer(_indexer);
liquidityConfigs[0] = LiquidityConfig({
sqrtPriceX96: 175983911958351096399483062,
tickLower: 122200,
tickUpper: -53000,
amount0Desired: 1000000000000000000000000,
amount1Desired: 0,
virtualAmount: 0,
penaltyMultiplier: 100
});
liquidityConfigs[1] = LiquidityConfig({
sqrtPriceX96: 555759188024637249212569346,
tickLower: 99200,
tickUpper: -30000,
amount0Desired: 1000000000000000000000000,
amount1Desired: 0,
virtualAmount: 0,
penaltyMultiplier: 100
});
liquidityConfigs[2] = LiquidityConfig({
sqrtPriceX96: 1755093813046398424555436057,
tickLower: 76000,
tickUpper: -6800,
amount0Desired: 1000000000000000000000000,
amount1Desired: 0,
virtualAmount: 0,
penaltyMultiplier: 100
});
liquidityConfigCount = 3;
if (_buybackPool != address(0)) {
buybackPool = _buybackPool;
}
if (_devAddress != address(0)) {
devAddress = _devAddress;
}
}
receive() external payable {}
function setConveyor(address _conveyor) external {
if (msg.sender != platformController) revert NotController();
conveyor = FactoryConveyor(_conveyor);
indexer.authorizeAddress(_conveyor);
conveyor.setIndexer(address(indexer));
}
function setBuybackPool(address pool) external {
if (msg.sender != platformController) revert NotController();
require(pool != address(0), "Pool is zero");
buybackPool = pool;
}
function setDevAddress(address _devAddress) external {
if (msg.sender != platformController) revert NotController();
require(_devAddress != address(0), "Dev address is zero");
devAddress = _devAddress;
}
function setIndexer(address _newIndexer) external {
if (msg.sender != platformController) revert NotController();
indexer = IIndexer(_newIndexer);
if (address(conveyor) != address(0)) {
conveyor.setIndexer(_newIndexer);
}
}
function setFactory(address _factory) external {
if (msg.sender != platformController) revert NotController();
FACTORY = _factory;
}
function deployAgent(
string memory _name,
string memory _symbol,
string memory _metadata,
bytes32 saltSeed,
uint256 configId
) public payable nonReentrant returns (uint256 tokensReceived) {
if (!deployCoinEnabled) revert DeploymentDisabled();
if (configId >= liquidityConfigCount) revert InvalidConfigId();
require(address(conveyor) != address(0), "Conveyor not set");
(bytes32 chosenSalt, address predicted) = conveyor.findSaltTokenLTWETH(
_name,
_symbol,
saltSeed
);
(address coinAddress, address predicted2) = conveyor.deployToken(
_name,
_symbol,
chosenSalt,
msg.sender
);
require(
coinAddress == predicted && predicted2 == predicted,
"Predicted mismatch"
);
tokenCreators[coinAddress] = msg.sender;
_setupLiquidity(coinAddress, configId);
tokensReceived = _handleInitialBuy(coinAddress, configId);
_storeTokenInfo(coinAddress, _name, _symbol, _metadata);
return tokensReceived;
}
function _setupLiquidity(address coinAddress, uint256 configId) internal {
provideLiquidity(coinAddress, WETH, configId);
}
function _toHex(bytes memory buffer) public pure returns (string memory) {
// Fixed buffer size for hexadecimal convertion
bytes memory converted = new bytes(buffer.length * 2);
bytes memory _base = "0123456789abcdef";
for (uint256 i = 0; i < buffer.length; i++) {
converted[i * 2] = _base[uint8(buffer[i]) / _base.length];
converted[i * 2 + 1] = _base[uint8(buffer[i]) % _base.length];
}
return string(abi.encodePacked("0x", converted));
}
function _handleInitialBuy(
address coinAddress,
uint256 /* configId */
) internal returns (uint256) {
if (msg.value == 0) return 0;
// 0) Preflight: ensure the router will target the same pool we created
address expected = IUniswapV3Factory(FACTORY).getPool(
coinAddress,
WETH,
FEE_TIER
);
require(expected != address(0), "initial buy: pool not found for fee");
require(
expected == tokenToPool[coinAddress],
"initial buy: router/factory pool mismatch"
);
require(expected.code.length > 0, "initial buy: pool has no code");
require(
IUniswapV3PoolState(expected).liquidity() > 0,
"initial buy: pool has zero active liquidity"
);
// 1) Wrap ETH -> WETH locally
IWETH(WETH).deposit{value: msg.value}();
// 2) Approve router if needed
if (IERC20(WETH).allowance(address(this), SWAP_ROUTER) < msg.value) {
IERC20(WETH).approve(SWAP_ROUTER, type(uint256).max);
}
// 3) Swap WETH -> token (no native value forwarded)
ISwapRouter02.ExactInputSingleParams memory params = ISwapRouter02
.ExactInputSingleParams({
tokenIn: WETH,
tokenOut: coinAddress,
fee: FEE_TIER,
recipient: address(this),
amountIn: msg.value,
amountOutMinimum: 0,
sqrtPriceLimitX96: 0
});
uint256 amountOut;
try ISwapRouter02(SWAP_ROUTER).exactInputSingle(params) returns (
uint256 out
) {
amountOut = out;
} catch Error(string memory reason) {
revert(string.concat("initial buy swap failed: ", reason));
} catch (bytes memory data) {
// data may be empty when the router called a non-existent pool
// _toHex(data) already has a 0x prefix; don't add another
revert(
string.concat("initial buy swap failed (raw): ", _toHex(data))
);
}
// 4) Send the bought tokens to the deployer
IERC20(coinAddress).transfer(msg.sender, amountOut);
// 5) Analytics/event
indexer.emitTokenPurchased(
msg.sender,
coinAddress,
msg.value,
amountOut
);
return amountOut;
}
function _storeTokenInfo(
address coinAddress,
string memory name,
string memory symbol,
string memory metadata
) internal {
TokenInfo memory newTokenInfo = TokenInfo({
tokenAddress: coinAddress,
name: name,
symbol: symbol,
deployer: msg.sender,
time: block.timestamp,
metadata: metadata,
marketCapInETH: 0,
nftId: tokenToNFTId[coinAddress],
totalFeesGenerated: 0
});
deployedTokens[tokenCount] = newTokenInfo;
tokenInfoByAddress[coinAddress] = newTokenInfo;
deployerTokens[msg.sender].push(coinAddress);
unchecked {
++tokenCount;
}
}
function getPenalty(uint256 ethAmount) public pure returns (uint256) {
if (ethAmount < 0.05 ether) return 0;
if (ethAmount >= 0.30 ether) return 5000;
uint256 slope = 18000;
uint256 delta = ethAmount - 0.05 ether;
return 500 + (delta * slope) / 1 ether;
}
function getAllTokensByDeployer(
address _deployer
) public view returns (address[] memory) {
return deployerTokens[_deployer];
}
function getDeploysByPage(
uint256 page,
uint256 order
) public view returns (TokenInfo[] memory) {
if (tokenCount == 0) revert NoTokensDeployed();
uint256 totalPages = (tokenCount + itemsPerPage - 1) / itemsPerPage;
if (page >= totalPages) revert PageOutOfRange();
uint256 start;
uint256 end;
uint256 j;
if (order == 0) {
start = tokenCount > (page + 1) * itemsPerPage
? tokenCount - (page + 1) * itemsPerPage
: 0;
end = tokenCount - page * itemsPerPage;
if (end > tokenCount) end = tokenCount;
} else {
start = page * itemsPerPage;
end = start + itemsPerPage;
if (end > tokenCount) end = tokenCount;
}
TokenInfo[] memory tokens = new TokenInfo[](end - start);
for (uint256 i = start; i < end; ) {
uint256 index = order == 0 ? end - 1 - (i - start) : i;
TokenInfo memory info = deployedTokens[index];
uint256 marketCap = getTokenMarketCap(info.tokenAddress);
tokens[j++] = TokenInfo({
tokenAddress: info.tokenAddress,
name: info.name,
symbol: info.symbol,
deployer: info.deployer,
time: info.time,
metadata: info.metadata,
marketCapInETH: marketCap,
nftId: info.nftId,
totalFeesGenerated: tokenFeesGenerated[info.tokenAddress]
});
unchecked {
++i;
}
}
return tokens;
}
function toggleDeployCoin() external {
if (msg.sender != platformController) revert NotController();
deployCoinEnabled = !deployCoinEnabled;
}
function setItemsPerPage(uint256 _itemsPerPage) external {
if (msg.sender != platformController) revert NotController();
if (_itemsPerPage == 0 || _itemsPerPage > 1000)
revert ItemsPerPageRange();
itemsPerPage = _itemsPerPage;
}
function setTokenCreator(address token, address newCreator) external {
if (msg.sender != platformController) revert NotController();
tokenCreators[token] = newCreator;
}
function createLiquidityConfig(
uint160 _sqrtPriceX96,
int24 _tickLower,
int24 _tickUpper,
uint256 _amount0Desired,
uint256 _amount1Desired,
uint256 _virtualAmount,
uint256 _penaltyMultiplier
) external returns (uint256 configId) {
if (msg.sender != platformController) revert NotController();
if (_penaltyMultiplier < 10 || _penaltyMultiplier > 500)
revert PenaltyMultiplierRange();
configId = liquidityConfigCount;
liquidityConfigs[configId] = LiquidityConfig({
sqrtPriceX96: _sqrtPriceX96,
tickLower: _tickLower,
tickUpper: _tickUpper,
amount0Desired: _amount0Desired,
amount1Desired: _amount1Desired,
virtualAmount: _virtualAmount,
penaltyMultiplier: _penaltyMultiplier
});
unchecked {
++liquidityConfigCount;
}
return configId;
}
function updateLiquidityConfig(
uint256 _configId,
uint160 _sqrtPriceX96,
int24 _tickLower,
int24 _tickUpper,
uint256 _amount0Desired,
uint256 _amount1Desired,
uint256 _virtualAmount,
uint256 _penaltyMultiplier
) external {
if (msg.sender != platformController) revert NotController();
if (_configId >= liquidityConfigCount) revert InvalidConfigId();
if (_penaltyMultiplier < 10 || _penaltyMultiplier > 500)
revert PenaltyMultiplierRange();
liquidityConfigs[_configId] = LiquidityConfig({
sqrtPriceX96: _sqrtPriceX96,
tickLower: _tickLower,
tickUpper: _tickUpper,
amount0Desired: _amount0Desired,
amount1Desired: _amount1Desired,
virtualAmount: _virtualAmount,
penaltyMultiplier: _penaltyMultiplier
});
}
function deleteLiquidityConfig(uint256 _configId) external {
if (msg.sender != platformController) revert NotController();
if (_configId >= liquidityConfigCount || _configId == 0)
revert InvalidConfigId();
delete liquidityConfigs[_configId];
}
function getLiquidityConfig(
uint256 _configId
) external view returns (LiquidityConfig memory) {
require(_configId < liquidityConfigCount, "Invalid config ID");
return liquidityConfigs[_configId];
}
function provideLiquidity(
address tokenA,
address tokenB,
uint256 configId
) internal {
if (tokenA >= tokenB) revert TokenMustBeToken0();
LiquidityConfig memory config = liquidityConfigs[configId];
address token0 = tokenA;
address token1 = tokenB;
IERC20(token0).approve(POSITION_MANAGER, type(uint256).max);
IERC20(token1).approve(POSITION_MANAGER, type(uint256).max);
INonfungiblePositionManager manager = INonfungiblePositionManager(
POSITION_MANAGER
);
int24 tickLower = -config.tickLower;
int24 tickUpper = config.tickUpper;
address pool = manager.createAndInitializePoolIfNecessary(
token0,
token1,
FEE_TIER,
config.sqrtPriceX96
);
tokenToPool[token0] = pool;
(uint256 tokenId, , , ) = manager.mint(
INonfungiblePositionManager.MintParams({
token0: token0,
token1: token1,
fee: FEE_TIER,
tickLower: tickLower,
tickUpper: tickUpper,
amount0Desired: config.amount0Desired,
amount1Desired: config.amount1Desired,
amount0Min: 0,
amount1Min: 0,
recipient: address(this),
deadline: block.timestamp
})
);
_storeNFTId(tokenA, tokenId);
}
function collectFeesAndBuyback(
address tokenAddress
)
external
nonReentrant
returns (
uint256 tokenFeesCollected,
uint256 wethFeesCollected,
uint256 creatorETHPaid
)
{
uint256 tokenId = tokenToNFTId[tokenAddress];
if (tokenId == 0) revert NoPosition();
address pool = tokenToPool[tokenAddress];
require(pool != address(0), "No pool");
address token0 = IUniswapV3PoolTokens(pool).token0();
address token1 = IUniswapV3PoolTokens(pool).token1();
if (token0 == WETH && token1 != WETH) {
(token0, token1) = (token1, token0);
}
if (token1 != WETH) revert MustBeWETH();
uint256 beforeToken0 = IERC20(token0).balanceOf(address(this));
uint256 beforeToken1 = IERC20(token1).balanceOf(address(this));
INonfungiblePositionManager(POSITION_MANAGER).collect(
INonfungiblePositionManager.CollectParams({
tokenId: tokenId,
recipient: address(this),
amount0Max: type(uint128).max,
amount1Max: type(uint128).max
})
);
uint256 collected0 = IERC20(token0).balanceOf(address(this)) -
beforeToken0;
uint256 collected1 = IERC20(token1).balanceOf(address(this)) -
beforeToken1;
tokenFeesCollected = collected0;
wethFeesCollected = collected1;
ethFeeGenerated += collected1;
if (collected1 > 0) {
_trackTokenFees(token0, collected1);
tokenFeesClaimed[token0] += collected1;
}
// Always burn non-ETH token fees
if (collected0 > 0) {
_burnOrSendToDead(token0, collected0);
}
uint256 platformWeth = 0;
if (collected1 > 0) {
address creator = tokenCreators[token0];
if (creator != address(0)) {
uint256 creatorAmount = (collected1 * 20) / 100;
platformWeth = collected1 - creatorAmount;
IWETH(WETH).withdraw(creatorAmount);
(bool ok, ) = payable(creator).call{value: creatorAmount}("");
require(ok, "Creator payout failed");
creatorETHPaid = creatorAmount;
} else {
platformWeth = collected1;
}
}
if (devAddress != address(0) && platformWeth > 0) {
uint256 devAmount = (platformWeth * 20) / 100;
platformWeth -= devAmount;
IWETH(WETH).withdraw(devAmount);
(bool ok, ) = payable(devAddress).call{value: devAmount}("");
require(ok, "Dev payout failed");
}
if (buybackPool != address(0) && platformWeth > 0) {
IWETH(WETH).withdraw(platformWeth);
(bool ok, ) = payable(buybackPool).call{value: platformWeth}("");
require(ok, "Buyback payout failed");
}
indexer.emitFeesCollected(tokenId, token0, collected0, collected1);
}
function withdrawFeesWETH() external {
if (msg.sender != platformController) revert NotController();
uint256 wethBalance = IERC20(WETH).balanceOf(address(this));
if (wethBalance == 0) revert NoWETHToWithdraw();
IWETH(WETH).withdraw(wethBalance);
(bool success, ) = msg.sender.call{value: wethBalance}("");
require(success, "ETH transfer failed");
}
function withdrawFeesETH() external {
if (msg.sender != platformController) revert NotController();
uint256 ethBalance = address(this).balance;
if (ethBalance == 0) revert NoETHToWithdraw();
(bool success, ) = msg.sender.call{value: ethBalance}("");
require(success, "ETH transfer failed");
}
function getTokenFeesGenerated(
address tokenAddress
) public view returns (uint256) {
return tokenFeesGenerated[tokenAddress];
}
function getTokenFeesClaimed(
address tokenAddress
) public view returns (uint256) {
return tokenFeesClaimed[tokenAddress];
}
function _trackTokenFees(address token, uint256 amount) internal {
tokenFeesGenerated[token] += amount;
}
function _storeNFTId(address token, uint256 nftId) internal {
tokenToNFTId[token] = nftId;
}
function _burnOrSendToDead(address token, uint256 amount) internal {
if (amount == 0) return;
try ERC20Burnable(token).burn(amount) {} catch {
IERC20(token).transfer(
0x000000000000000000000000000000000000dEaD,
amount
);
}
}
function getTokenStats(
address tokenAddress
) external view returns (
uint256 marketCapInETH,
uint256 totalFeesGenerated,
address creatorAddress
) {
creatorAddress = tokenCreators[tokenAddress];
uint256 currentMarketCap = getTokenMarketCap(tokenAddress);
uint256 feesGenerated = tokenFeesGenerated[tokenAddress];
return (
currentMarketCap,
feesGenerated,
creatorAddress
);
}
function getTokenMarketCap(
address tokenAddress
) public view returns (uint256 marketCapInWETH) {
address WETH = INonfungiblePositionManager(POSITION_MANAGER).WETH9();
address factory = INonfungiblePositionManager(POSITION_MANAGER)
.factory();
address pool = IUniswapV3Factory(factory).getPool(
tokenAddress,
WETH,
FEE_TIER
);
if (pool == address(0)) return 0;
uint256 totalSupply = IERC20(tokenAddress).totalSupply();
(uint160 sqrtPriceX96, , , , , , ) = IUniswapV3Pool(pool).slot0();
if (sqrtPriceX96 == 0 || totalSupply == 0) return 0;
bool tokenIsToken0 = tokenAddress < WETH;
if (tokenIsToken0) {
uint256 priceX192 = uint256(sqrtPriceX96) * uint256(sqrtPriceX96);
marketCapInWETH = Math.mulDiv(totalSupply, priceX192, 1 << 192);
} else {
uint256 priceX192 = uint256(sqrtPriceX96) * uint256(sqrtPriceX96);
marketCapInWETH = Math.mulDiv(totalSupply, 1 << 192, priceX192);
}
}
}"
},
"src/v2/FactoryConveyor.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "./Token.sol";
contract FactoryConveyor {
address public immutable factory;
address public immutable WETH = WETH_ADDRESS;
uint256 public constant MAX_SALT_TRIES = 1024;
IIndexer public indexer;
error OnlyFactory();
modifier onlyFactory() {
if (msg.sender != factory) revert OnlyFactory();
_;
}
constructor(address _factory, address _indexer) {
factory = _factory;
indexer = IIndexer(_indexer);
}
function setIndexer(address _newIndexer) external onlyFactory {
indexer = IIndexer(_newIndexer);
}
function _tokenInitCode(
string memory name,
string memory symbol
) internal view returns (bytes memory) {
return
abi.encodePacked(
type(AgentToken).creationCode,
abi.encode(name, symbol, factory, address(indexer))
);
}
function _predictCreate2(
bytes32 salt,
bytes32 initCodeHash
) internal view returns (address) {
bytes32 h = keccak256(
abi.encodePacked(bytes1(0xff), address(this), salt, initCodeHash)
);
return address(uint160(uint256(h)));
}
function getTokenBytecode(
string memory name,
string memory symbol
) external view returns (bytes memory) {
return _tokenInitCode(name, symbol);
}
function findSaltTokenLTWETH(
string memory name,
string memory symbol,
bytes32 baseSalt
) external view onlyFactory returns (bytes32 saltFound, address predicted) {
bytes memory initCode = _tokenInitCode(name, symbol);
bytes32 initHash = keccak256(initCode);
uint160 wethNum = uint160(WETH);
for (uint256 i; i < MAX_SALT_TRIES; ) {
bytes32 saltCand = keccak256(abi.encodePacked(baseSalt, i));
address addr = _predictCreate2(saltCand, initHash);
if (uint160(addr) < wethNum) {
return (saltCand, addr);
}
unchecked {
++i;
}
}
revert SaltSearchFailed();
}
function deployToken(
string memory name,
string memory symbol,
bytes32 salt,
address originalDeployer
) external onlyFactory returns (address token, address predicted) {
bytes memory initCode = _tokenInitCode(name, symbol);
bytes32 initHash = keccak256(initCode);
AgentToken t = new AgentToken{salt: salt}(
name,
symbol,
factory,
address(indexer)
);
token = address(t);
predicted = _predictCreate2(salt, initHash);
require(token == predicted, "CREATE2 address mismatch");
indexer.emitSaltBruteforced(salt, token);
indexer.emitERC20TokenCreated(token, originalDeployer);
indexer.authorizeAddress(token);
}
}
"
},
"lib/v4-core/lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}
"
},
"src/v2/Token.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
// $$$$$$\ $$\
// $$ __$$\ $$ |
// $$ / \__|$$\ $$\ $$$$$$$\ $$$$$$\ $$$$$$\ $$$$$$\
// \$$$$$$\ $$ | $$ |$$ __$$\\_$$ _| $$ __$$\ $$ __$$\
// \____$$\ $$ | $$ |$$ | $$ | $$ | $$ / $$ |$$ | \__|
// $$\ $$ |$$ | $$ |$$ | $$ | $$ |$$\ $$ | $$ |$$ |
// \$$$$$$ |\$$$$$$$ |$$ | $$ | \$$$$ |\$$$$$$ |$$ |
// \______/ \____$$ |\__| \__| \____/ \______/ \__|
// $$\ $$ |
// \$$$$$$ |
// \______/
address constant WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address constant UNISWAP_V3_POSITION_MANAGER = 0xC36442b4a4522E871399CD717aBDD847Ab11FE88;
address constant UNISWAP_V3_FACTORY = 0x1F98431c8aD98523631AE4a59f267346ea31F984;
address constant UNISWAP_V3_SWAP_ROUTER = 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45;
uint24 constant FEE_TIER_10000 = 10000;
interface IWETH {
function deposit() external payable;
function withdraw(uint256 amount) external;
}
interface IUniswapV3PoolState {
function liquidity() external view returns (uint128);
}
interface IUniswapV3Factory {
function getPool(
address tokenA,
address tokenB,
uint24 fee
) external view returns (address);
}
interface IUniswapV3Pool {
function slot0()
external
view
returns (
uint160 sqrtPriceX96,
int24 tick,
uint16 observationIndex,
uint16 observationCardinality,
uint16 observationCardinalityNext,
uint32 feeProtocol,
bool unlocked
);
function feeGrowthGlobal0X128() external view returns (uint256);
function feeGrowthGlobal1X128() external view returns (uint256);
}
interface IUniswapV3PoolTokens {
function token0() external view returns (address);
function token1() external view returns (address);
}
interface ISwapRouter02 {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
function exactInputSingle(
ExactInputSingleParams calldata params
) external payable returns (uint256 amountOut);
}
interface INonfungiblePositionManager {
struct MintParams {
address token0;
address token1;
uint24 fee;
int24 tickLower;
int24 tickUpper;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
address recipient;
uint256 deadline;
}
function factory() external view returns (address);
function WETH9() external view returns (address);
function positions(
uint256 tokenId
)
external
view
returns (
uint96 nonce,
address operator,
address token0,
address token1,
uint24 fee,
int24 tickLower,
int24 tickUpper,
uint128 liquidity,
uint256 feeGrowthInside0LastX128,
uint256 feeGrowthInside1LastX128,
uint128 tokensOwed0,
uint128 tokensOwed1
);
function createAndInitializePoolIfNecessary(
address token0,
address token1,
uint24 fee,
uint160 sqrtPriceX96
) external returns (address pool);
function mint(
MintParams calldata params
)
external
returns (
uint256 tokenId,
uint128 liquidity,
uint256 amount0,
uint256 amount1
);
struct CollectParams {
uint256 tokenId;
address recipient;
uint128 amount0Max;
uint128 amount1Max;
}
function collect(
CollectParams calldata params
) external payable returns (uint256 amount0, uint256 amount1);
}
interface IFactoryPoolView {
function tokenToPool(address token) external view returns (address);
}
interface IIndexer {
function emitERC20TokenCreated(
address tokenAddress,
address deployer
) external;
function emitSaltBruteforced(
bytes32 usedSalt,
address predictedToken
) external;
function emitFeesCollected(
uint256 tokenId,
address token,
uint256 tokenAmount,
uint256 ethAmount
) external;
function emitTokenPurchased(
address buyer,
address tokenOut,
uint256 ethSpent,
uint256 tokensReceived
) external;
function emitBuy(
address buyer,
address pool,
address token,
uint256 amountTokens,
uint160 sqrtPriceX96,
uint256 priceX96,
uint256 ethAmount,
uint256 totalFeesETH,
uint256 totalFeesToken
) external;
function emitSell(
address seller,
address pool,
address token,
uint256 amountTokens,
uint160 sqrtPriceX96,
uint256 priceX96,
uint256 ethAmount,
uint256 totalFeesETH,
uint256 totalFeesToken
) external;
function authorizeAddress(address _contract) external;
}
error NotController();
error DeploymentDisabled();
error InvalidConfigId();
error SaltSearchFailed();
error TokenMustBeToken0();
error MustBeWETH();
error NoWETHToWithdraw();
error NoETHToWithdraw();
error BatchRange();
error ItemsPerPageRange();
error PenaltyMultiplierRange();
error NoTokensDeployed();
error PageOutOfRange();
error InternalOnly();
error NoPosition();
error NotAuthorized();
contract AgentToken is ERC20, ERC20Burnable {
using Math for uint256;
address public platform;
IIndexer public indexer;
uint256 private launchBlock;
uint256 private maxTxAmount;
uint256 private constant LAUNCH_PERIOD = 5;
uint256 private constant MAX_WALLET_PERCENTAGE = 2;
address public constant POSITION_MANAGER = UNISWAP_V3_POSITION_MANAGER;
address public constant WETH = WETH_ADDRESS;
mapping(address => uint256) private tokensFromPoolPerOrigin;
constructor(
string memory _name,
string memory _symbol,
address _platform,
address _indexer
) ERC20(_name, _symbol) {
platform = _platform;
indexer = IIndexer(_indexer);
launchBlock = block.number;
uint256 totalTokens = 1_000_000 * 10 ** decimals();
maxTxAmount = (totalTokens * MAX_WALLET_PERCENTAGE) / 100;
_mint(_platform, totalTokens);
}
function owner() public pure returns (address) {
return address(0);
}
function _update(
address from,
address to,
uint256 value
) internal override {
if (
block.number > launchBlock &&
block.number <= launchBlock + LAUNCH_PERIOD
) {
address factory = INonfungiblePositionManager(POSITION_MANAGER)
.factory();
address pool = IUniswapV3Factory(factory).getPool(
address(this),
WETH,
FEE_TIER_10000
);
if (from == pool && to != platform) {
tokensFromPoolPerOrigin[tx.origin] += value;
require(
tokensFromPoolPerOrigin[tx.origin] <=
(maxTxAmount * 110) / 100,
"Keeping 2% pool Limits In Kontrol"
);
}
if (to != platform && to != pool && from != address(0)) {
require(
balanceOf(to) + value <= maxTxAmount,
"Max wallet limit exceeded during launch period"
);
}
}
if (
block.number == launchBlock &&
from != address(0) &&
to != platform &&
from != platform
) {
revert("No buys allowed during launch block!");
}
super._update(from, to, value);
address factoryPool = IFactoryPoolView(platform).tokenToPool(
address(this)
);
if (
factoryPool != address(0) &&
(from == factoryPool || to == factoryPool)
) {
(uint160 sqrtPriceX96, , , , , , ) = IUniswapV3Pool(factoryPool)
.slot0();
uint256 priceX96 = Math.mulDiv(
uint256(sqrtPriceX96),
uint256(sqrtPriceX96),
1 << 96
);
uint256 feeGrowthETH = IUniswapV3Pool(factoryPool)
.feeGrowthGlobal1X128();
uint256 feeGrowthToken = IUniswapV3Pool(factoryPool)
.feeGrowthGlobal0X128();
bool tokenIsToken0 = address(this) < WETH;
uint256 ethAmount;
if (tokenIsToken0) {
uint256 priceX192 = Math.mulDiv(uint256(sqrtPriceX96), uint256(sqrtPriceX96), 1);
ethAmount = Math.mulDiv(value, priceX192, 1 << 192);
} else {
uint256 priceX192 = Math.mulDiv(uint256(sqrtPriceX96), uint256(sqrtPriceX96), 1);
ethAmount = Math.mulDiv(value, 1 << 192, priceX192);
}
if (from == factoryPool && to != address(0)) {
try
indexer.emitBuy(
to,
factoryPool,
address(this),
value,
sqrtPriceX96,
priceX96,
ethAmount,
feeGrowthETH,
feeGrowthToken
)
{} catch {}
} else if (to == factoryPool && from != address(0)) {
try
indexer.emitSell(
from,
factoryPool,
address(this),
value,
sqrtPriceX96,
priceX96,
ethAmount,
feeGrowthETH,
feeGrowthToken
)
{} catch {}
}
}
}
function getTokenPair() public view returns (address, address, address) {
address find_factory = INonfungiblePositionManager(POSITION_MANAGER)
.factory();
address find_pool = IUniswapV3Factory(find_factory).getPool(
address(this),
WETH,
FEE_TIER_10000
);
return (find_pool, address(this), find_factory);
}
function isLaunchPeriodActive() public view returns (bool) {
return block.number <= launchBlock + LAUNCH_PERIOD;
}
}
"
},
"lib/v4-core/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Burnable.sol)
pragma solidity ^0.8.20;
import {ERC20} from "../ERC20.sol";
import {Context} from "../../../utils/Context.sol";
/**
* @dev Extension of {ERC20} that allows token holders to destroy both their own
* tokens and those that they have an allowance for, in a way that can be
* recognized off-chain (via event analysis).
*/
abstract contract ERC20Burnable is Context, ERC20 {
/**
* @dev Destroys a `value` amount of tokens from the caller.
*
* See {ERC20-_burn}.
*/
function burn(uint256 value) public virtual {
_burn(_msgSender(), value);
}
/**
* @dev Destroys a `value` amount of tokens from `account`, deducting from
* the caller's allowance.
*
* See {ERC20-_burn} and {ERC20-allowance}.
*
* Requirements:
*
* - the caller must have allowance for ``accounts``'s tokens of at least
* `value`.
*/
function burnFrom(address account, uint256 value) public virtual {
_spendAllowance(account, _msgSender(), value);
_burn(account, value);
}
}
"
},
"lib/v4-core/lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*/
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
mapping(address account => uint256) private _balances;
mapping(address account => mapping(address spender => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `value`.
*/
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `value`.
* - the caller must have allowance for ``from``'s tokens of at least
* `value`.
*/
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
/**
* @dev Moves a `value` amount of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
/**
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
* this function.
*
* Emits a {Transfer} event.
*/
function _update(address from, address to, uint256 value) internal virtual {
if (from == address(0)) {
// Overflow check required: The rest of the code assumes that totalSupply never overflows
_totalSupply += value;
} else {
uint256 fromBalance = _balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
// Overflow not possible: value <= fromBalance <= totalSupply.
_balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
// Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
_totalSupply -= value;
}
} else {
unchecked {
// Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
_balances[to] += value;
}
}
emit Transfer(from, to, value);
}
/**
* @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
* Relies on the `_update` mechanism
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
/**
* @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead
*/
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
/**
* @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
/**
* @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
*
* By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
* `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
* `Approval` event during `transferFrom` operations.
*
* Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
* true using the following override:
* ```
* function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
* super._approve(owner, spender, value, true);
* }
* ```
*
* Requirements are the same as {_approve}.
*/
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `value`.
*
* Does not update the allowance value in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Does not emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}
"
},
"lib/v4-core/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
"
},
"lib/v4-core/lib/openzeppelin-contracts/contracts/utils/math/Math.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
Submitted on: 2025-11-01 14:32:46
Comments
Log in to comment.
No comments yet.