Sonic Blaze Testnet

Contract

0x59137e5F896e910EFddC8F274DF58932b558D475
Transaction Hash
Method
Block
From
To
Execute Applicat...152440082025-01-24 21:03:534 days ago1737752633IN
0x59137e5F...2b558D475
0 S0.003072341.1
Propose Agent152439992025-01-24 21:03:504 days ago1737752630IN
0x59137e5F...2b558D475
0 S0.00028671.1
Execute Applicat...152408352025-01-24 20:45:064 days ago1737751506IN
0x59137e5F...2b558D475
0 S0.003072341.1
Propose Agent152408262025-01-24 20:45:044 days ago1737751504IN
0x59137e5F...2b558D475
0 S0.00028671.1
Execute Applicat...152404872025-01-24 20:43:054 days ago1737751385IN
0x59137e5F...2b558D475
0 S0.003091151.1
Propose Agent152404782025-01-24 20:43:024 days ago1737751382IN
0x59137e5F...2b558D475
0 S0.000237511.1
Set Token Tax Pa...152404612025-01-24 20:42:564 days ago1737751376IN
0x59137e5F...2b558D475
0 S0.000040431.1
Set Token Supply...152404542025-01-24 20:42:544 days ago1737751374IN
0x59137e5F...2b558D475
0 S0.000063721.1
Propose Agent152394722025-01-24 20:36:594 days ago1737751019IN
0x59137e5F...2b558D475
0 S0.000237511.1
Set Token Tax Pa...152394592025-01-24 20:36:544 days ago1737751014IN
0x59137e5F...2b558D475
0 S0.000040431.1
Set Token Supply...152394502025-01-24 20:36:514 days ago1737751011IN
0x59137e5F...2b558D475
0 S0.000048661.1
Set Application ...152391922025-01-24 20:35:134 days ago1737750913IN
0x59137e5F...2b558D475
0 S0.000033141.1
Propose Agent152390832025-01-24 20:34:334 days ago1737750873IN
0x59137e5F...2b558D475
0 S0.000237511.1
Set Token Tax Pa...152390702025-01-24 20:34:274 days ago1737750867IN
0x59137e5F...2b558D475
0 S0.000049671.1
Set Token Supply...152390632025-01-24 20:34:254 days ago1737750865IN
0x59137e5F...2b558D475
0 S0.000064061.1
Propose Agent152388712025-01-24 20:33:154 days ago1737750795IN
0x59137e5F...2b558D475
0 S0.000237511.1
Set Token Tax Pa...152388562025-01-24 20:33:094 days ago1737750789IN
0x59137e5F...2b558D475
0 S0.000040451.1
Set Token Supply...152388482025-01-24 20:33:064 days ago1737750786IN
0x59137e5F...2b558D475
0 S0.00006411.1
Propose Agent152386952025-01-24 20:32:084 days ago1737750728IN
0x59137e5F...2b558D475
0 S0.000237511.1
Set Token Tax Pa...152386812025-01-24 20:32:034 days ago1737750723IN
0x59137e5F...2b558D475
0 S0.000040451.1
Set Token Supply...152386722025-01-24 20:32:004 days ago1737750720IN
0x59137e5F...2b558D475
0 S0.000064121.1
Propose Agent152385252025-01-24 20:31:044 days ago1737750664IN
0x59137e5F...2b558D475
0 S0.000237511.1
Set Token Tax Pa...152385122025-01-24 20:30:584 days ago1737750658IN
0x59137e5F...2b558D475
0 S0.000040451.1
Set Token Supply...152385042025-01-24 20:30:554 days ago1737750655IN
0x59137e5F...2b558D475
0 S0.000051851.1
Propose Agent152382092025-01-24 20:29:074 days ago1737750547IN
0x59137e5F...2b558D475
0 S0.000237511.1
View all transactions

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
152440082025-01-24 21:03:534 days ago1737752633
0x59137e5F...2b558D475
0 S
152440082025-01-24 21:03:534 days ago1737752633
0x59137e5F...2b558D475
0 S
152440082025-01-24 21:03:534 days ago1737752633
0x59137e5F...2b558D475
0 S
152440082025-01-24 21:03:534 days ago1737752633
0x59137e5F...2b558D475
0 S
152440082025-01-24 21:03:534 days ago1737752633
0x59137e5F...2b558D475
 Contract Creation0 S
152439992025-01-24 21:03:504 days ago1737752630
0x59137e5F...2b558D475
0 S
152439992025-01-24 21:03:504 days ago1737752630
0x59137e5F...2b558D475
0 S
152439992025-01-24 21:03:504 days ago1737752630
0x59137e5F...2b558D475
0 S
152408352025-01-24 20:45:064 days ago1737751506
0x59137e5F...2b558D475
0 S
152408352025-01-24 20:45:064 days ago1737751506
0x59137e5F...2b558D475
0 S
152408352025-01-24 20:45:064 days ago1737751506
0x59137e5F...2b558D475
0 S
152408352025-01-24 20:45:064 days ago1737751506
0x59137e5F...2b558D475
0 S
152408352025-01-24 20:45:064 days ago1737751506
0x59137e5F...2b558D475
 Contract Creation0 S
152408262025-01-24 20:45:044 days ago1737751504
0x59137e5F...2b558D475
0 S
152408262025-01-24 20:45:044 days ago1737751504
0x59137e5F...2b558D475
0 S
152408262025-01-24 20:45:044 days ago1737751504
0x59137e5F...2b558D475
0 S
152404872025-01-24 20:43:054 days ago1737751385
0x59137e5F...2b558D475
0 S
152404872025-01-24 20:43:054 days ago1737751385
0x59137e5F...2b558D475
0 S
152404872025-01-24 20:43:054 days ago1737751385
0x59137e5F...2b558D475
0 S
152404872025-01-24 20:43:054 days ago1737751385
0x59137e5F...2b558D475
0 S
152404872025-01-24 20:43:054 days ago1737751385
0x59137e5F...2b558D475
 Contract Creation0 S
152404782025-01-24 20:43:024 days ago1737751382
0x59137e5F...2b558D475
0 S
152404782025-01-24 20:43:024 days ago1737751382
0x59137e5F...2b558D475
0 S
152404782025-01-24 20:43:024 days ago1737751382
0x59137e5F...2b558D475
0 S
152394722025-01-24 20:36:594 days ago1737751019
0x59137e5F...2b558D475
0 S
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
TheFactory

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 26 : TheFactory.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/proxy/Clones.sol";
import "@openzeppelin/contracts/governance/IGovernor.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
// import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts/proxy/utils/Initializable.sol";
// import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
// import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
// import "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
import "@openzeppelin/contracts/utils/Pausable.sol";

import "./ITheFactory.sol";
import "./virtuals/IAgentToken.sol";
// import "./IAgentVeToken.sol";
// import "./IAgentDAO.sol";
// import "./IAgentNft.sol";
// import "./libs/IERC6551Registry.sol";
import "./interfaces/IUniswapV2Factory.sol";
import "./interfaces/IUniswapV2Router02.sol";

contract TheFactory is
    ITheFactory,
    Initializable,
    // AccessControlUpgradeable,
    AccessControl,
    // PausableUpgradeable
    Pausable
{
    using SafeERC20 for IERC20;

    uint256 private _nextId;
    address public tokenImplementation;
    // address public daoImplementation;
    // address public nft;
    // address public tbaRegistry; // Token bound account
    uint256 public applicationThreshold;

    address[] public allTokens;
    // address[] public allDAOs;

    address public assetToken; // Base currency
    uint256 public maturityDuration; // Staking duration in seconds for initial LP. eg: 10years

    bytes32 public constant WITHDRAW_ROLE = keccak256("WITHDRAW_ROLE"); // Able to withdraw and execute applications

    event NewPersona(
        uint256 virtualId,
        address token,
        // address dao,
        // address tba,
        // address veToken,
        address lp
    );
    event NewApplication(uint256 id);

    enum ApplicationStatus {
        Active,
        Executed,
        Withdrawn
    }

    struct Application {
        string name;
        string symbol;
        string tokenURI;
        ApplicationStatus status;
        uint256 withdrawableAmount;
        address proposer;
        uint8[] cores;
        // uint256 proposalEndBlock;
        // uint256 virtualId;
        // bytes32 tbaSalt;
        // address tbaImplementation;
        // uint32 daoVotingPeriod;
        // uint256 daoThreshold;
    }

    mapping(uint256 => Application) private _applications;

    event ApplicationThresholdUpdated(uint256 newThreshold);
    // event GovUpdated(address newGov);
    // event ImplContractsUpdated(address token, address dao);

    // address private _vault; // Vault to hold all Virtual NFTs

    bool internal locked;

    modifier noReentrant() {
        require(!locked, "cannot reenter");
        locked = true;
        _;
        locked = false;
    }

    ///////////////////////////////////////////////////////////////
    // V2 Storage
    ///////////////////////////////////////////////////////////////
    address[] public allTradingTokens;
    address private _uniswapRouter;
    // address public veTokenImplementation;
    address private _tokenAdmin;
    // address public defaultDelegatee;

    // Default agent token params
    bytes private _tokenSupplyParams;
    bytes private _tokenTaxParams;

    ///////////////////////////////////////////////////////////////
    // V4 Storage
    ///////////////////////////////////////////////////////////////
    // The follow 2 variables maps only custom ERC20 to agent applications
    // mapping(address => uint256) private _tokenApplication;
    // mapping(uint256 => address) private _applicationToken;

    ///////////////////////////////////////////////////////////////

    // /// @custom:oz-upgrades-unsafe-allow constructor
    // constructor() {
    //     // _disableInitializers();
    // }

    function initialize(
        address tokenImplementation_,
        // address veTokenImplementation_,
        // address daoImplementation_,
        // address tbaRegistry_,
        // address nft_,
        // uint256 applicationThreshold_,
        // address vault_,
        uint256 nextId_,
        address assetToken_
    ) public initializer {
        // __Pausable_init();
        // __AccessControl_init();

        tokenImplementation = tokenImplementation_;
        // veTokenImplementation = veTokenImplementation_;
        // daoImplementation = daoImplementation_;
        assetToken = assetToken_;
        // tbaRegistry = tbaRegistry_;
        // nft = nft_;
        // applicationThreshold = applicationThreshold_;
        _nextId = nextId_;
        // _nextId = 0;
        _grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
        // _vault = vault_;
    }

    function getApplication(
        uint256 proposalId
    ) public view returns (Application memory) {
        return _applications[proposalId];
    }

    function proposeAgent(
        string memory name,
        string memory symbol,
        string memory tokenURI,
        uint8[] memory cores
        // ,
        // bytes32 tbaSalt,
        // address tbaImplementation,
        // uint32 daoVotingPeriod,
        // uint256 daoThreshold
    ) public whenNotPaused returns (uint256) {
        address sender = _msgSender();
        require(
            IERC20(assetToken).balanceOf(sender) >= applicationThreshold,
            "Insufficient asset token"
        );
        require(
            IERC20(assetToken).allowance(sender, address(this)) >=
                applicationThreshold,
            "Insufficient asset token allowance"
        );
        require(cores.length > 0, "Cores must be provided");

        IERC20(assetToken).safeTransferFrom(
            sender,
            address(this),
            applicationThreshold
        );

        uint256 id = _nextId++;
        // uint256 proposalEndBlock = block.number; // No longer required in v2
        Application memory application = Application(
            name,
            symbol,
            tokenURI,
            ApplicationStatus.Active,
            applicationThreshold,
            sender,
            cores
            // ,
            // proposalEndBlock
            // ,
            // 0,
            // tbaSalt,
            // tbaImplementation,
            // daoVotingPeriod,
            // daoThreshold
        );
        _applications[id] = application;
        emit NewApplication(id);

        return id;
    }

    function withdraw(uint256 id) public noReentrant {
        Application storage application = _applications[id];

        require(
            msg.sender == application.proposer ||
                hasRole(WITHDRAW_ROLE, msg.sender),
            "Not proposer"
        );

        require(
            application.status == ApplicationStatus.Active,
            "Application is not active"
        );

        // require(
        //     block.number > application.proposalEndBlock,
        //     "Application is not matured yet"
        // );

        uint256 withdrawableAmount = application.withdrawableAmount;

        application.withdrawableAmount = 0;
        application.status = ApplicationStatus.Withdrawn;

        IERC20(assetToken).safeTransfer(
            application.proposer,
            withdrawableAmount
        );

        // address customToken = _applicationToken[id];
        // if (customToken != address(0)) {
        //     IERC20(customToken).safeTransfer(
        //         application.proposer,
        //         IERC20(customToken).balanceOf(address(this))
        //     );

        //     _tokenApplication[customToken] = 0;
        //     _applicationToken[id] = address(0);
        // }
    }

    function _executeApplication(
        uint256 id,
        bool canStake,
        bytes memory tokenSupplyParams_
    ) internal {
        require(
            _applications[id].status == ApplicationStatus.Active,
            "Application is not active"
        );

        require(_tokenAdmin != address(0), "Token admin not set");

        Application storage application = _applications[id];

        uint256 initialAmount = application.withdrawableAmount;
        application.withdrawableAmount = 0;
        application.status = ApplicationStatus.Executed;

        // C1 & C2
        address token = address(0);
        // token = _applicationToken[id];
        address lp = address(0);
        // if (token == address(0)) {
            token = _createNewAgentToken(
                application.name,
                application.symbol,
                tokenSupplyParams_
            );
            lp = IAgentToken(token).liquidityPools()[0];
            IERC20(assetToken).safeTransfer(token, initialAmount);
            IAgentToken(token).addInitialLiquidity(address(this));
        // } else {
        //     // Custom token
        //     lp = _createPair(token);
        //     IERC20(token).forceApprove(_uniswapRouter, type(uint256).max);
        //     IERC20(assetToken).forceApprove(_uniswapRouter, initialAmount);
        //     // Add the liquidity:
        //     IUniswapV2Router02(_uniswapRouter).addLiquidity(
        //         token,
        //         assetToken,
        //         IERC20(token).balanceOf(address(this)),
        //         initialAmount,
        //         0,
        //         0,
        //         address(this),
        //         block.timestamp
        //     );
        // }

        // // C3
        // address veToken = _createNewAgentVeToken(
        //     string.concat("Staked ", application.name),
        //     string.concat("s", application.symbol),
        //     lp,
        //     application.proposer,
        //     canStake
        // );

        // // C4
        // string memory daoName = string.concat(application.name, " DAO");
        // address payable dao = payable(
        //     _createNewDAO(
        //         daoName,
        //         IVotes(veToken),
        //         application.daoVotingPeriod,
        //         application.daoThreshold
        //     )
        // );

        // // C5
        // uint256 virtualId = IAgentNft(nft).nextVirtualId();
        // IAgentNft(nft).mint(
        //     virtualId,
        //     _vault,
        //     application.tokenURI,
        //     dao,
        //     application.proposer,
        //     application.cores,
        //     lp,
        //     token
        // );
        // application.virtualId = virtualId;

        // // C6
        // uint256 chainId;
        // assembly {
        //     chainId := chainid()
        // }
        // address tbaAddress = IERC6551Registry(tbaRegistry).createAccount(
        //     application.tbaImplementation,
        //     application.tbaSalt,
        //     chainId,
        //     nft,
        //     virtualId
        // );
        // IAgentNft(nft).setTBA(virtualId, tbaAddress);

        // // C7
        // IERC20(lp).approve(veToken, type(uint256).max);
        // IAgentVeToken(veToken).stake(
        //     IERC20(lp).balanceOf(address(this)),
        //     application.proposer,
        //     defaultDelegatee
        // );

        // emit NewPersona(virtualId, token, dao, tbaAddress, veToken, lp);
        // emit NewPersona(virtualId, token, lp);

    }

    function executeApplication(uint256 id, bool canStake) public noReentrant {
        // This will bootstrap an Agent with following components:
        // C1: Agent Token
        // C2: LP Pool + Initial liquidity
        // C3: Agent veToken
        // C4: Agent DAO
        // C5: Agent NFT
        // C6: TBA
        // C7: Stake liquidity token to get veToken

        Application storage application = _applications[id];

        require(
            msg.sender == application.proposer ||
                hasRole(WITHDRAW_ROLE, msg.sender),
            "Not proposer"
        );

        _executeApplication(id, canStake, _tokenSupplyParams);
    }

    // function _createNewDAO(
    //     string memory name,
    //     IVotes token,
    //     uint32 daoVotingPeriod,
    //     uint256 daoThreshold
    // ) internal returns (address instance) {
    //     instance = Clones.clone(daoImplementation);
    //     IAgentDAO(instance).initialize(
    //         name,
    //         token,
    //         nft,
    //         daoThreshold,
    //         daoVotingPeriod
    //     );

    //     allDAOs.push(instance);
    //     return instance;
    // }

    function _createNewAgentToken(
        string memory name,
        string memory symbol,
        bytes memory tokenSupplyParams_
    ) internal returns (address instance) {
        instance = Clones.clone(tokenImplementation);
        IAgentToken(instance).initialize(
            [_tokenAdmin, _uniswapRouter, assetToken],
            abi.encode(name, symbol),
            tokenSupplyParams_,
            _tokenTaxParams
        );

        allTradingTokens.push(instance);
        return instance;
    }

    // function _createNewAgentVeToken(
    //     string memory name,
    //     string memory symbol,
    //     address stakingAsset,
    //     address founder,
    //     bool canStake
    // ) internal returns (address instance) {
    //     instance = Clones.clone(veTokenImplementation);
    //     IAgentVeToken(instance).initialize(
    //         name,
    //         symbol,
    //         founder,
    //         stakingAsset,
    //         block.timestamp + maturityDuration,
    //         address(nft),
    //         canStake
    //     );

    //     allTokens.push(instance);
    //     return instance;
    // }

    function totalAgents() public view returns (uint256) {
        return allTokens.length;
    }

    function setApplicationThreshold(
        uint256 newThreshold
    ) public onlyRole(DEFAULT_ADMIN_ROLE) {
        applicationThreshold = newThreshold;
        emit ApplicationThresholdUpdated(newThreshold);
    }

    // function setVault(address newVault) public onlyRole(DEFAULT_ADMIN_ROLE) {
    //     _vault = newVault;
    // }

    function setImplementations(
        // address veToken,
        // address dao,
        address token
    ) public onlyRole(DEFAULT_ADMIN_ROLE) {
        tokenImplementation = token;
        // daoImplementation = dao;
        // veTokenImplementation = veToken;
    }

    function setMaturityDuration(
        uint256 newDuration
    ) public onlyRole(DEFAULT_ADMIN_ROLE) {
        maturityDuration = newDuration;
    }

    function setUniswapRouter(
        address router
    ) public onlyRole(DEFAULT_ADMIN_ROLE) {
        _uniswapRouter = router;
    }

    function setTokenAdmin(
        address newTokenAdmin
    ) public onlyRole(DEFAULT_ADMIN_ROLE) {
        _tokenAdmin = newTokenAdmin;
    }

    function setTokenSupplyParams(
        uint256 maxSupply,
        uint256 lpSupply,
        uint256 vaultSupply,
        uint256 maxTokensPerWallet,
        uint256 maxTokensPerTxn,
        uint256 botProtectionDurationInSeconds,
        address vault
    ) public onlyRole(DEFAULT_ADMIN_ROLE) {
        _tokenSupplyParams = abi.encode(
            maxSupply,
            lpSupply,
            vaultSupply,
            maxTokensPerWallet,
            maxTokensPerTxn,
            botProtectionDurationInSeconds,
            vault
        );
    }

    function setTokenTaxParams(
        uint256 projectBuyTaxBasisPoints,
        uint256 projectSellTaxBasisPoints,
        uint256 taxSwapThresholdBasisPoints,
        address projectTaxRecipient
    ) public onlyRole(DEFAULT_ADMIN_ROLE) {
        _tokenTaxParams = abi.encode(
            projectBuyTaxBasisPoints,
            projectSellTaxBasisPoints,
            taxSwapThresholdBasisPoints,
            projectTaxRecipient
        );
    }

    function setAssetToken(
        address newToken
    ) public onlyRole(DEFAULT_ADMIN_ROLE) {
        assetToken = newToken;
    }

    function pause() public onlyRole(DEFAULT_ADMIN_ROLE) {
        _pause();
    }

    function unpause() public onlyRole(DEFAULT_ADMIN_ROLE) {
        _unpause();
    }

    // function _msgSender()
    //     internal
    //     view
    //     // override(ContextUpgradeable)
    //     returns (address sender)
    // {
    //     sender = ContextUpgradeable._msgSender();
    // }

    // function _msgData()
    //     internal
    //     view
    //     // override(ContextUpgradeable)
    //     returns (bytes calldata)
    // {
    //     return ContextUpgradeable._msgData();
    // }

    // function setDefaultDelegatee(
    //     address newDelegatee
    // ) public onlyRole(DEFAULT_ADMIN_ROLE) {
    //     defaultDelegatee = newDelegatee;
    // }

    // // Bootstrap Agent with existing ERC20 tokens
    // function initFromToken(
    //     address tokenAddr,
    //     uint8[] memory cores,
    //     bytes32 tbaSalt,
    //     address tbaImplementation,
    //     uint32 daoVotingPeriod,
    //     uint256 daoThreshold,
    //     uint256 initialLP
    // ) public whenNotPaused returns (uint256) {
    //     address sender = _msgSender();
    //     require(_tokenApplication[tokenAddr] == 0, "Token already exists");

    //     require(isCompatibleToken(tokenAddr), "Unsupported token");

    //     require(
    //         IERC20(assetToken).balanceOf(sender) >= applicationThreshold,
    //         "Insufficient asset token"
    //     );

    //     require(
    //         IERC20(assetToken).allowance(sender, address(this)) >=
    //             applicationThreshold,
    //         "Insufficient asset token allowance"
    //     );

    //     require(cores.length > 0, "Cores must be provided");

    //     require(initialLP > 0, "InitialLP must be greater than 0");

    //     IERC20(tokenAddr).safeTransferFrom(sender, address(this), initialLP);

    //     IERC20(assetToken).safeTransferFrom(
    //         sender,
    //         address(this),
    //         applicationThreshold
    //     );

    //     uint256 id = _nextId++;
    //     _tokenApplication[tokenAddr] = id;
    //     _applicationToken[id] = tokenAddr;

    //     Application memory application = Application(
    //         IAgentToken(tokenAddr).name(),
    //         IAgentToken(tokenAddr).symbol(),
    //         "",
    //         ApplicationStatus.Active,
    //         applicationThreshold,
    //         sender,
    //         cores,
    //         block.number,
    //         0,
    //         tbaSalt,
    //         tbaImplementation,
    //         daoVotingPeriod,
    //         daoThreshold
    //     );
    //     _applications[id] = application;
    //     emit NewApplication(id);

    //     return id;
    // }

    // function executeTokenApplication(
    //     uint256 id,
    //     bool canStake
    // ) public noReentrant {
    //     // This will bootstrap an Agent with following components:
    //     // C2: LP Pool + Initial liquidity
    //     // C3: Agent veToken
    //     // C4: Agent DAO
    //     // C5: Agent NFT
    //     // C6: TBA
    //     // C7: Stake liquidity token to get veToken

    //     Application storage application = _applications[id];

    //     require(
    //         msg.sender == application.proposer ||
    //             hasRole(WITHDRAW_ROLE, msg.sender),
    //         "Not proposer"
    //     );

    //     require(
    //         _applicationToken[id] != address(0),
    //         "Not custom token application"
    //     );

    //     _executeApplication(id, canStake, _tokenSupplyParams);
    // }

    // function isCompatibleToken(address tokenAddr) public view returns (bool) {
    //     try IAgentToken(tokenAddr).name() returns (string memory) {
    //         try IAgentToken(tokenAddr).symbol() returns (string memory) {
    //             try IAgentToken(tokenAddr).totalSupply() returns (uint256) {
    //                 try
    //                     IAgentToken(tokenAddr).balanceOf(address(this))
    //                 returns (uint256) {
    //                     return true;
    //                 } catch {
    //                     return false;
    //                 }
    //             } catch {
    //                 return false;
    //             }
    //         } catch {
    //             return false;
    //         }
    //     } catch {
    //         return false;
    //     }
    // }

    function _createPair(
        address tokenAddr
    ) internal returns (address uniswapV2Pair_) {
        
        IUniswapV2Factory factory = IUniswapV2Factory(
            IUniswapV2Router02(_uniswapRouter).factory()
        );

        require(
            factory.getPair(tokenAddr, assetToken) == address(0),
            "pool already exists"
        );

        uniswapV2Pair_ = factory.createPair(tokenAddr, assetToken);

        return (uniswapV2Pair_);
    }
}

File 2 of 26 : AccessControl.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)

pragma solidity ^0.8.20;

import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```solidity
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```solidity
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
 * to enforce additional security measures for this role.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address account => bool) hasRole;
        bytes32 adminRole;
    }

    mapping(bytes32 role => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with an {AccessControlUnauthorizedAccount} error including the required role.
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual returns (bool) {
        return _roles[role].hasRole[account];
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
     * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
     * is missing `role`.
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert AccessControlUnauthorizedAccount(account, role);
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleGranted} event.
     */
    function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleRevoked} event.
     */
    function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address callerConfirmation) public virtual {
        if (callerConfirmation != _msgSender()) {
            revert AccessControlBadConfirmation();
        }

        _revokeRole(role, callerConfirmation);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
        if (!hasRole(role, account)) {
            _roles[role].hasRole[account] = true;
            emit RoleGranted(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
        if (hasRole(role, account)) {
            _roles[role].hasRole[account] = false;
            emit RoleRevoked(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }
}

File 3 of 26 : IAccessControl.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/IAccessControl.sol)

pragma solidity ^0.8.20;

/**
 * @dev External interface of AccessControl declared to support ERC-165 detection.
 */
interface IAccessControl {
    /**
     * @dev The `account` is missing a role.
     */
    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);

    /**
     * @dev The caller of a function is not the expected one.
     *
     * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
     */
    error AccessControlBadConfirmation();

    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).
     * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     */
    function renounceRole(bytes32 role, address callerConfirmation) external;
}

File 4 of 26 : IGovernor.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (governance/IGovernor.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../interfaces/IERC165.sol";
import {IERC6372} from "../interfaces/IERC6372.sol";

/**
 * @dev Interface of the {Governor} core.
 *
 * NOTE: Event parameters lack the `indexed` keyword for compatibility with GovernorBravo events.
 * Making event parameters `indexed` affects how events are decoded, potentially breaking existing indexers.
 */
interface IGovernor is IERC165, IERC6372 {
    enum ProposalState {
        Pending,
        Active,
        Canceled,
        Defeated,
        Succeeded,
        Queued,
        Expired,
        Executed
    }

    /**
     * @dev Empty proposal or a mismatch between the parameters length for a proposal call.
     */
    error GovernorInvalidProposalLength(uint256 targets, uint256 calldatas, uint256 values);

    /**
     * @dev The vote was already cast.
     */
    error GovernorAlreadyCastVote(address voter);

    /**
     * @dev Token deposits are disabled in this contract.
     */
    error GovernorDisabledDeposit();

    /**
     * @dev The `account` is not a proposer.
     */
    error GovernorOnlyProposer(address account);

    /**
     * @dev The `account` is not the governance executor.
     */
    error GovernorOnlyExecutor(address account);

    /**
     * @dev The `proposalId` doesn't exist.
     */
    error GovernorNonexistentProposal(uint256 proposalId);

    /**
     * @dev The current state of a proposal is not the required for performing an operation.
     * The `expectedStates` is a bitmap with the bits enabled for each ProposalState enum position
     * counting from right to left.
     *
     * NOTE: If `expectedState` is `bytes32(0)`, the proposal is expected to not be in any state (i.e. not exist).
     * This is the case when a proposal that is expected to be unset is already initiated (the proposal is duplicated).
     *
     * See {Governor-_encodeStateBitmap}.
     */
    error GovernorUnexpectedProposalState(uint256 proposalId, ProposalState current, bytes32 expectedStates);

    /**
     * @dev The voting period set is not a valid period.
     */
    error GovernorInvalidVotingPeriod(uint256 votingPeriod);

    /**
     * @dev The `proposer` does not have the required votes to create a proposal.
     */
    error GovernorInsufficientProposerVotes(address proposer, uint256 votes, uint256 threshold);

    /**
     * @dev The `proposer` is not allowed to create a proposal.
     */
    error GovernorRestrictedProposer(address proposer);

    /**
     * @dev The vote type used is not valid for the corresponding counting module.
     */
    error GovernorInvalidVoteType();

    /**
     * @dev The provided params buffer is not supported by the counting module.
     */
    error GovernorInvalidVoteParams();

    /**
     * @dev Queue operation is not implemented for this governor. Execute should be called directly.
     */
    error GovernorQueueNotImplemented();

    /**
     * @dev The proposal hasn't been queued yet.
     */
    error GovernorNotQueuedProposal(uint256 proposalId);

    /**
     * @dev The proposal has already been queued.
     */
    error GovernorAlreadyQueuedProposal(uint256 proposalId);

    /**
     * @dev The provided signature is not valid for the expected `voter`.
     * If the `voter` is a contract, the signature is not valid using {IERC1271-isValidSignature}.
     */
    error GovernorInvalidSignature(address voter);

    /**
     * @dev Emitted when a proposal is created.
     */
    event ProposalCreated(
        uint256 proposalId,
        address proposer,
        address[] targets,
        uint256[] values,
        string[] signatures,
        bytes[] calldatas,
        uint256 voteStart,
        uint256 voteEnd,
        string description
    );

    /**
     * @dev Emitted when a proposal is queued.
     */
    event ProposalQueued(uint256 proposalId, uint256 etaSeconds);

    /**
     * @dev Emitted when a proposal is executed.
     */
    event ProposalExecuted(uint256 proposalId);

    /**
     * @dev Emitted when a proposal is canceled.
     */
    event ProposalCanceled(uint256 proposalId);

    /**
     * @dev Emitted when a vote is cast without params.
     *
     * Note: `support` values should be seen as buckets. Their interpretation depends on the voting module used.
     */
    event VoteCast(address indexed voter, uint256 proposalId, uint8 support, uint256 weight, string reason);

    /**
     * @dev Emitted when a vote is cast with params.
     *
     * Note: `support` values should be seen as buckets. Their interpretation depends on the voting module used.
     * `params` are additional encoded parameters. Their interpretation  also depends on the voting module used.
     */
    event VoteCastWithParams(
        address indexed voter,
        uint256 proposalId,
        uint8 support,
        uint256 weight,
        string reason,
        bytes params
    );

    /**
     * @notice module:core
     * @dev Name of the governor instance (used in building the EIP-712 domain separator).
     */
    function name() external view returns (string memory);

    /**
     * @notice module:core
     * @dev Version of the governor instance (used in building the EIP-712 domain separator). Default: "1"
     */
    function version() external view returns (string memory);

    /**
     * @notice module:voting
     * @dev A description of the possible `support` values for {castVote} and the way these votes are counted, meant to
     * be consumed by UIs to show correct vote options and interpret the results. The string is a URL-encoded sequence of
     * key-value pairs that each describe one aspect, for example `support=bravo&quorum=for,abstain`.
     *
     * There are 2 standard keys: `support` and `quorum`.
     *
     * - `support=bravo` refers to the vote options 0 = Against, 1 = For, 2 = Abstain, as in `GovernorBravo`.
     * - `quorum=bravo` means that only For votes are counted towards quorum.
     * - `quorum=for,abstain` means that both For and Abstain votes are counted towards quorum.
     *
     * If a counting module makes use of encoded `params`, it should  include this under a `params` key with a unique
     * name that describes the behavior. For example:
     *
     * - `params=fractional` might refer to a scheme where votes are divided fractionally between for/against/abstain.
     * - `params=erc721` might refer to a scheme where specific NFTs are delegated to vote.
     *
     * NOTE: The string can be decoded by the standard
     * https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams[`URLSearchParams`]
     * JavaScript class.
     */
    // solhint-disable-next-line func-name-mixedcase
    function COUNTING_MODE() external view returns (string memory);

    /**
     * @notice module:core
     * @dev Hashing function used to (re)build the proposal id from the proposal details..
     */
    function hashProposal(
        address[] memory targets,
        uint256[] memory values,
        bytes[] memory calldatas,
        bytes32 descriptionHash
    ) external pure returns (uint256);

    /**
     * @notice module:core
     * @dev Current state of a proposal, following Compound's convention
     */
    function state(uint256 proposalId) external view returns (ProposalState);

    /**
     * @notice module:core
     * @dev The number of votes required in order for a voter to become a proposer.
     */
    function proposalThreshold() external view returns (uint256);

    /**
     * @notice module:core
     * @dev Timepoint used to retrieve user's votes and quorum. If using block number (as per Compound's Comp), the
     * snapshot is performed at the end of this block. Hence, voting for this proposal starts at the beginning of the
     * following block.
     */
    function proposalSnapshot(uint256 proposalId) external view returns (uint256);

    /**
     * @notice module:core
     * @dev Timepoint at which votes close. If using block number, votes close at the end of this block, so it is
     * possible to cast a vote during this block.
     */
    function proposalDeadline(uint256 proposalId) external view returns (uint256);

    /**
     * @notice module:core
     * @dev The account that created a proposal.
     */
    function proposalProposer(uint256 proposalId) external view returns (address);

    /**
     * @notice module:core
     * @dev The time when a queued proposal becomes executable ("ETA"). Unlike {proposalSnapshot} and
     * {proposalDeadline}, this doesn't use the governor clock, and instead relies on the executor's clock which may be
     * different. In most cases this will be a timestamp.
     */
    function proposalEta(uint256 proposalId) external view returns (uint256);

    /**
     * @notice module:core
     * @dev Whether a proposal needs to be queued before execution.
     */
    function proposalNeedsQueuing(uint256 proposalId) external view returns (bool);

    /**
     * @notice module:user-config
     * @dev Delay, between the proposal is created and the vote starts. The unit this duration is expressed in depends
     * on the clock (see ERC-6372) this contract uses.
     *
     * This can be increased to leave time for users to buy voting power, or delegate it, before the voting of a
     * proposal starts.
     *
     * NOTE: While this interface returns a uint256, timepoints are stored as uint48 following the ERC-6372 clock type.
     * Consequently this value must fit in a uint48 (when added to the current clock). See {IERC6372-clock}.
     */
    function votingDelay() external view returns (uint256);

    /**
     * @notice module:user-config
     * @dev Delay between the vote start and vote end. The unit this duration is expressed in depends on the clock
     * (see ERC-6372) this contract uses.
     *
     * NOTE: The {votingDelay} can delay the start of the vote. This must be considered when setting the voting
     * duration compared to the voting delay.
     *
     * NOTE: This value is stored when the proposal is submitted so that possible changes to the value do not affect
     * proposals that have already been submitted. The type used to save it is a uint32. Consequently, while this
     * interface returns a uint256, the value it returns should fit in a uint32.
     */
    function votingPeriod() external view returns (uint256);

    /**
     * @notice module:user-config
     * @dev Minimum number of cast voted required for a proposal to be successful.
     *
     * NOTE: The `timepoint` parameter corresponds to the snapshot used for counting vote. This allows to scale the
     * quorum depending on values such as the totalSupply of a token at this timepoint (see {ERC20Votes}).
     */
    function quorum(uint256 timepoint) external view returns (uint256);

    /**
     * @notice module:reputation
     * @dev Voting power of an `account` at a specific `timepoint`.
     *
     * Note: this can be implemented in a number of ways, for example by reading the delegated balance from one (or
     * multiple), {ERC20Votes} tokens.
     */
    function getVotes(address account, uint256 timepoint) external view returns (uint256);

    /**
     * @notice module:reputation
     * @dev Voting power of an `account` at a specific `timepoint` given additional encoded parameters.
     */
    function getVotesWithParams(
        address account,
        uint256 timepoint,
        bytes memory params
    ) external view returns (uint256);

    /**
     * @notice module:voting
     * @dev Returns whether `account` has cast a vote on `proposalId`.
     */
    function hasVoted(uint256 proposalId, address account) external view returns (bool);

    /**
     * @dev Create a new proposal. Vote start after a delay specified by {IGovernor-votingDelay} and lasts for a
     * duration specified by {IGovernor-votingPeriod}.
     *
     * Emits a {ProposalCreated} event.
     *
     * NOTE: The state of the Governor and `targets` may change between the proposal creation and its execution.
     * This may be the result of third party actions on the targeted contracts, or other governor proposals.
     * For example, the balance of this contract could be updated or its access control permissions may be modified,
     * possibly compromising the proposal's ability to execute successfully (e.g. the governor doesn't have enough
     * value to cover a proposal with multiple transfers).
     */
    function propose(
        address[] memory targets,
        uint256[] memory values,
        bytes[] memory calldatas,
        string memory description
    ) external returns (uint256 proposalId);

    /**
     * @dev Queue a proposal. Some governors require this step to be performed before execution can happen. If queuing
     * is not necessary, this function may revert.
     * Queuing a proposal requires the quorum to be reached, the vote to be successful, and the deadline to be reached.
     *
     * Emits a {ProposalQueued} event.
     */
    function queue(
        address[] memory targets,
        uint256[] memory values,
        bytes[] memory calldatas,
        bytes32 descriptionHash
    ) external returns (uint256 proposalId);

    /**
     * @dev Execute a successful proposal. This requires the quorum to be reached, the vote to be successful, and the
     * deadline to be reached. Depending on the governor it might also be required that the proposal was queued and
     * that some delay passed.
     *
     * Emits a {ProposalExecuted} event.
     *
     * NOTE: Some modules can modify the requirements for execution, for example by adding an additional timelock.
     */
    function execute(
        address[] memory targets,
        uint256[] memory values,
        bytes[] memory calldatas,
        bytes32 descriptionHash
    ) external payable returns (uint256 proposalId);

    /**
     * @dev Cancel a proposal. A proposal is cancellable by the proposer, but only while it is Pending state, i.e.
     * before the vote starts.
     *
     * Emits a {ProposalCanceled} event.
     */
    function cancel(
        address[] memory targets,
        uint256[] memory values,
        bytes[] memory calldatas,
        bytes32 descriptionHash
    ) external returns (uint256 proposalId);

    /**
     * @dev Cast a vote
     *
     * Emits a {VoteCast} event.
     */
    function castVote(uint256 proposalId, uint8 support) external returns (uint256 balance);

    /**
     * @dev Cast a vote with a reason
     *
     * Emits a {VoteCast} event.
     */
    function castVoteWithReason(
        uint256 proposalId,
        uint8 support,
        string calldata reason
    ) external returns (uint256 balance);

    /**
     * @dev Cast a vote with a reason and additional encoded parameters
     *
     * Emits a {VoteCast} or {VoteCastWithParams} event depending on the length of params.
     */
    function castVoteWithReasonAndParams(
        uint256 proposalId,
        uint8 support,
        string calldata reason,
        bytes memory params
    ) external returns (uint256 balance);

    /**
     * @dev Cast a vote using the voter's signature, including ERC-1271 signature support.
     *
     * Emits a {VoteCast} event.
     */
    function castVoteBySig(
        uint256 proposalId,
        uint8 support,
        address voter,
        bytes memory signature
    ) external returns (uint256 balance);

    /**
     * @dev Cast a vote with a reason and additional encoded parameters using the voter's signature,
     * including ERC-1271 signature support.
     *
     * Emits a {VoteCast} or {VoteCastWithParams} event depending on the length of params.
     */
    function castVoteWithReasonAndParamsBySig(
        uint256 proposalId,
        uint8 support,
        address voter,
        string calldata reason,
        bytes memory params,
        bytes memory signature
    ) external returns (uint256 balance);
}

File 5 of 26 : IERC1363.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)

pragma solidity ^0.8.20;

import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";

/**
 * @title IERC1363
 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
 *
 * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
 * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
 */
interface IERC1363 is IERC20, IERC165 {
    /*
     * Note: the ERC-165 identifier for this interface is 0xb0202a11.
     * 0xb0202a11 ===
     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^
     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
     */

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @param data Additional data with no specified format, sent in call to `spender`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}

File 6 of 26 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../utils/introspection/IERC165.sol";

File 7 of 26 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../token/ERC20/IERC20.sol";

File 8 of 26 : IERC6372.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC6372.sol)

pragma solidity ^0.8.20;

interface IERC6372 {
    /**
     * @dev Clock used for flagging checkpoints. Can be overridden to implement timestamp based checkpoints (and voting).
     */
    function clock() external view returns (uint48);

    /**
     * @dev Description of the clock
     */
    // solhint-disable-next-line func-name-mixedcase
    function CLOCK_MODE() external view returns (string memory);
}

File 9 of 26 : Clones.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (proxy/Clones.sol)

pragma solidity ^0.8.20;

import {Create2} from "../utils/Create2.sol";
import {Errors} from "../utils/Errors.sol";

/**
 * @dev https://eips.ethereum.org/EIPS/eip-1167[ERC-1167] is a standard for
 * deploying minimal proxy contracts, also known as "clones".
 *
 * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
 * > a minimal bytecode implementation that delegates all calls to a known, fixed address.
 *
 * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
 * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
 * deterministic method.
 */
library Clones {
    error CloneArgumentsTooLong();

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create opcode, which should never revert.
     */
    function clone(address implementation) internal returns (address instance) {
        return clone(implementation, 0);
    }

    /**
     * @dev Same as {xref-Clones-clone-address-}[clone], but with a `value` parameter to send native currency
     * to the new contract.
     *
     * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
     * to always have enough balance for new deployments. Consider exposing this function under a payable method.
     */
    function clone(address implementation, uint256 value) internal returns (address instance) {
        if (address(this).balance < value) {
            revert Errors.InsufficientBalance(address(this).balance, value);
        }
        assembly ("memory-safe") {
            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
            // of the `implementation` address with the bytecode before the address.
            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
            instance := create(value, 0x09, 0x37)
        }
        if (instance == address(0)) {
            revert Errors.FailedDeployment();
        }
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create2 opcode and a `salt` to deterministically deploy
     * the clone. Using the same `implementation` and `salt` multiple times will revert, since
     * the clones cannot be deployed twice at the same address.
     */
    function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
        return cloneDeterministic(implementation, salt, 0);
    }

    /**
     * @dev Same as {xref-Clones-cloneDeterministic-address-bytes32-}[cloneDeterministic], but with
     * a `value` parameter to send native currency to the new contract.
     *
     * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
     * to always have enough balance for new deployments. Consider exposing this function under a payable method.
     */
    function cloneDeterministic(
        address implementation,
        bytes32 salt,
        uint256 value
    ) internal returns (address instance) {
        if (address(this).balance < value) {
            revert Errors.InsufficientBalance(address(this).balance, value);
        }
        assembly ("memory-safe") {
            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
            // of the `implementation` address with the bytecode before the address.
            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
            instance := create2(value, 0x09, 0x37, salt)
        }
        if (instance == address(0)) {
            revert Errors.FailedDeployment();
        }
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        assembly ("memory-safe") {
            let ptr := mload(0x40)
            mstore(add(ptr, 0x38), deployer)
            mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
            mstore(add(ptr, 0x14), implementation)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
            mstore(add(ptr, 0x58), salt)
            mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
            predicted := and(keccak256(add(ptr, 0x43), 0x55), 0xffffffffffffffffffffffffffffffffffffffff)
        }
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt
    ) internal view returns (address predicted) {
        return predictDeterministicAddress(implementation, salt, address(this));
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behavior of `implementation` with custom
     * immutable arguments. These are provided through `args` and cannot be changed after deployment. To
     * access the arguments within the implementation, use {fetchCloneArgs}.
     *
     * This function uses the create opcode, which should never revert.
     */
    function cloneWithImmutableArgs(address implementation, bytes memory args) internal returns (address instance) {
        return cloneWithImmutableArgs(implementation, args, 0);
    }

    /**
     * @dev Same as {xref-Clones-cloneWithImmutableArgs-address-bytes-}[cloneWithImmutableArgs], but with a `value`
     * parameter to send native currency to the new contract.
     *
     * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
     * to always have enough balance for new deployments. Consider exposing this function under a payable method.
     */
    function cloneWithImmutableArgs(
        address implementation,
        bytes memory args,
        uint256 value
    ) internal returns (address instance) {
        if (address(this).balance < value) {
            revert Errors.InsufficientBalance(address(this).balance, value);
        }
        bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);
        assembly ("memory-safe") {
            instance := create(value, add(bytecode, 0x20), mload(bytecode))
        }
        if (instance == address(0)) {
            revert Errors.FailedDeployment();
        }
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation` with custom
     * immutable arguments. These are provided through `args` and cannot be changed after deployment. To
     * access the arguments within the implementation, use {fetchCloneArgs}.
     *
     * This function uses the create2 opcode and a `salt` to deterministically deploy the clone. Using the same
     * `implementation`, `args` and `salt` multiple times will revert, since the clones cannot be deployed twice
     * at the same address.
     */
    function cloneDeterministicWithImmutableArgs(
        address implementation,
        bytes memory args,
        bytes32 salt
    ) internal returns (address instance) {
        return cloneDeterministicWithImmutableArgs(implementation, args, salt, 0);
    }

    /**
     * @dev Same as {xref-Clones-cloneDeterministicWithImmutableArgs-address-bytes-bytes32-}[cloneDeterministicWithImmutableArgs],
     * but with a `value` parameter to send native currency to the new contract.
     *
     * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)
     * to always have enough balance for new deployments. Consider exposing this function under a payable method.
     */
    function cloneDeterministicWithImmutableArgs(
        address implementation,
        bytes memory args,
        bytes32 salt,
        uint256 value
    ) internal returns (address instance) {
        bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);
        return Create2.deploy(value, salt, bytecode);
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministicWithImmutableArgs}.
     */
    function predictDeterministicAddressWithImmutableArgs(
        address implementation,
        bytes memory args,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);
        return Create2.computeAddress(salt, keccak256(bytecode), deployer);
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministicWithImmutableArgs}.
     */
    function predictDeterministicAddressWithImmutableArgs(
        address implementation,
        bytes memory args,
        bytes32 salt
    ) internal view returns (address predicted) {
        return predictDeterministicAddressWithImmutableArgs(implementation, args, salt, address(this));
    }

    /**
     * @dev Get the immutable args attached to a clone.
     *
     * - If `instance` is a clone that was deployed using `clone` or `cloneDeterministic`, this
     *   function will return an empty array.
     * - If `instance` is a clone that was deployed using `cloneWithImmutableArgs` or
     *   `cloneDeterministicWithImmutableArgs`, this function will return the args array used at
     *   creation.
     * - If `instance` is NOT a clone deployed using this library, the behavior is undefined. This
     *   function should only be used to check addresses that are known to be clones.
     */
    function fetchCloneArgs(address instance) internal view returns (bytes memory) {
        bytes memory result = new bytes(instance.code.length - 45); // revert if length is too short
        assembly ("memory-safe") {
            extcodecopy(instance, add(result, 32), 45, mload(result))
        }
        return result;
    }

    /**
     * @dev Helper that prepares the initcode of the proxy with immutable args.
     *
     * An assembly variant of this function requires copying the `args` array, which can be efficiently done using
     * `mcopy`. Unfortunately, that opcode is not available before cancun. A pure solidity implementation using
     * abi.encodePacked is more expensive but also more portable and easier to review.
     *
     * NOTE: https://eips.ethereum.org/EIPS/eip-170[EIP-170] limits the length of the contract code to 24576 bytes.
     * With the proxy code taking 45 bytes, that limits the length of the immutable args to 24531 bytes.
     */
    function _cloneCodeWithImmutableArgs(
        address implementation,
        bytes memory args
    ) private pure returns (bytes memory) {
        if (args.length > 24531) revert CloneArgumentsTooLong();
        return
            abi.encodePacked(
                hex"61",
                uint16(args.length + 45),
                hex"3d81600a3d39f3363d3d373d3d3d363d73",
                implementation,
                hex"5af43d82803e903d91602b57fd5bf3",
                args
            );
    }
}

File 10 of 26 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.20;

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```solidity
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 *
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Storage of the initializable contract.
     *
     * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
     * when using with upgradeable contracts.
     *
     * @custom:storage-location erc7201:openzeppelin.storage.Initializable
     */
    struct InitializableStorage {
        /**
         * @dev Indicates that the contract has been initialized.
         */
        uint64 _initialized;
        /**
         * @dev Indicates that the contract is in the process of being initialized.
         */
        bool _initializing;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;

    /**
     * @dev The contract is already initialized.
     */
    error InvalidInitialization();

    /**
     * @dev The contract is not initializing.
     */
    error NotInitializing();

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint64 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
     * production.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        // Cache values to avoid duplicated sloads
        bool isTopLevelCall = !$._initializing;
        uint64 initialized = $._initialized;

        // Allowed calls:
        // - initialSetup: the contract is not in the initializing state and no previous version was
        //                 initialized
        // - construction: the contract is initialized at version 1 (no reininitialization) and the
        //                 current contract is just being deployed
        bool initialSetup = initialized == 0 && isTopLevelCall;
        bool construction = initialized == 1 && address(this).code.length == 0;

        if (!initialSetup && !construction) {
            revert InvalidInitialization();
        }
        $._initialized = 1;
        if (isTopLevelCall) {
            $._initializing = true;
        }
        _;
        if (isTopLevelCall) {
            $._initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint64 version) {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing || $._initialized >= version) {
            revert InvalidInitialization();
        }
        $._initialized = version;
        $._initializing = true;
        _;
        $._initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        _checkInitializing();
        _;
    }

    /**
     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
     */
    function _checkInitializing() internal view virtual {
        if (!_isInitializing()) {
            revert NotInitializing();
        }
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing) {
            revert InvalidInitialization();
        }
        if ($._initialized != type(uint64).max) {
            $._initialized = type(uint64).max;
            emit Initialized(type(uint64).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint64) {
        return _getInitializableStorage()._initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _getInitializableStorage()._initializing;
    }

    /**
     * @dev Returns a pointer to the storage namespace.
     */
    // solhint-disable-next-line var-name-mixedcase
    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
        assembly {
            $.slot := INITIALIZABLE_STORAGE
        }
    }
}

File 11 of 26 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC-20 standard.
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 12 of 26 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
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);
}

File 13 of 26 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC-20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    /**
     * @dev An operation with an ERC-20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     *
     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
     * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
     * set here.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            safeTransfer(token, to, value);
        } else if (!token.transferAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferFromAndCallRelaxed(
        IERC1363 token,
        address from,
        address to,
        uint256 value,
        bytes memory data
    ) internal {
        if (to.code.length == 0) {
            safeTransferFrom(token, from, to, value);
        } else if (!token.transferFromAndCall(from, to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
     * once without retrying, and relies on the returned value to be true.
     *
     * Reverts if the returned value is other than `true`.
     */
    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            forceApprove(token, to, value);
        } else if (!token.approveAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            // bubble errors
            if iszero(success) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0, returndatasize())
                revert(ptr, returndatasize())
            }
            returnSize := returndatasize()
            returnValue := mload(0)
        }

        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            returnSize := returndatasize()
            returnValue := mload(0)
        }
        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
    }
}

File 14 of 26 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

File 15 of 26 : Create2.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Create2.sol)

pragma solidity ^0.8.20;

import {Errors} from "./Errors.sol";

/**
 * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.
 * `CREATE2` can be used to compute in advance the address where a smart
 * contract will be deployed, which allows for interesting new mechanisms known
 * as 'counterfactual interactions'.
 *
 * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more
 * information.
 */
library Create2 {
    /**
     * @dev There's no code to deploy.
     */
    error Create2EmptyBytecode();

    /**
     * @dev Deploys a contract using `CREATE2`. The address where the contract
     * will be deployed can be known in advance via {computeAddress}.
     *
     * The bytecode for a contract can be obtained from Solidity with
     * `type(contractName).creationCode`.
     *
     * Requirements:
     *
     * - `bytecode` must not be empty.
     * - `salt` must have not been used for `bytecode` already.
     * - the factory must have a balance of at least `amount`.
     * - if `amount` is non-zero, `bytecode` must have a `payable` constructor.
     */
    function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) {
        if (address(this).balance < amount) {
            revert Errors.InsufficientBalance(address(this).balance, amount);
        }
        if (bytecode.length == 0) {
            revert Create2EmptyBytecode();
        }
        assembly ("memory-safe") {
            addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
            // if no address was created, and returndata is not empty, bubble revert
            if and(iszero(addr), not(iszero(returndatasize()))) {
                let p := mload(0x40)
                returndatacopy(p, 0, returndatasize())
                revert(p, returndatasize())
            }
        }
        if (addr == address(0)) {
            revert Errors.FailedDeployment();
        }
    }

    /**
     * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the
     * `bytecodeHash` or `salt` will result in a new destination address.
     */
    function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {
        return computeAddress(salt, bytecodeHash, address(this));
    }

    /**
     * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at
     * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.
     */
    function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) {
        assembly ("memory-safe") {
            let ptr := mload(0x40) // Get free memory pointer

            // |                   | ↓ ptr ...  ↓ ptr + 0x0B (start) ...  ↓ ptr + 0x20 ...  ↓ ptr + 0x40 ...   |
            // |-------------------|---------------------------------------------------------------------------|
            // | bytecodeHash      |                                                        CCCCCCCCCCCCC...CC |
            // | salt              |                                      BBBBBBBBBBBBB...BB                   |
            // | deployer          | 000000...0000AAAAAAAAAAAAAAAAAAA...AA                                     |
            // | 0xFF              |            FF                                                             |
            // |-------------------|---------------------------------------------------------------------------|
            // | memory            | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC |
            // | keccak(start, 85) |            ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ |

            mstore(add(ptr, 0x40), bytecodeHash)
            mstore(add(ptr, 0x20), salt)
            mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes
            let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff
            mstore8(start, 0xff)
            addr := and(keccak256(start, 85), 0xffffffffffffffffffffffffffffffffffffffff)
        }
    }
}

File 16 of 26 : Errors.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)

pragma solidity ^0.8.20;

/**
 * @dev Collection of common custom errors used in multiple contracts
 *
 * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
 * It is recommended to avoid relying on the error API for critical functionality.
 *
 * _Available since v5.1._
 */
library Errors {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error InsufficientBalance(uint256 balance, uint256 needed);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedCall();

    /**
     * @dev The deployment failed.
     */
    error FailedDeployment();

    /**
     * @dev A necessary precompile is missing.
     */
    error MissingPrecompile(address);
}

File 17 of 26 : ERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)

pragma solidity ^0.8.20;

import {IERC165} from "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

File 18 of 26 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 19 of 26 : Pausable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    bool private _paused;

    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    /**
     * @dev The operation failed because the contract is paused.
     */
    error EnforcedPause();

    /**
     * @dev The operation failed because the contract is not paused.
     */
    error ExpectedPause();

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor() {
        _paused = false;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        if (paused()) {
            revert EnforcedPause();
        }
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        if (!paused()) {
            revert ExpectedPause();
        }
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

File 20 of 26 : IUniswapV2Factory.sol
pragma solidity >=0.5.0;

interface IUniswapV2Factory {
    event PairCreated(address indexed token0, address indexed token1, address pair, uint);

    function feeTo() external view returns (address);
    function feeToSetter() external view returns (address);

    function getPair(address tokenA, address tokenB) external view returns (address pair);
    function allPairs(uint) external view returns (address pair);
    function allPairsLength() external view returns (uint);

    function createPair(address tokenA, address tokenB) external returns (address pair);

    function setFeeTo(address) external;
    function setFeeToSetter(address) external;
}

File 21 of 26 : IUniswapV2Router01.sol
pragma solidity >=0.6.2;

interface IUniswapV2Router01 {
    function factory() external pure returns (address);
    function WETH() external pure returns (address);

    function addLiquidity(
        address tokenA,
        address tokenB,
        uint amountADesired,
        uint amountBDesired,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB, uint liquidity);
    function addLiquidityETH(
        address token,
        uint amountTokenDesired,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external payable returns (uint amountToken, uint amountETH, uint liquidity);
    function removeLiquidity(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETH(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountToken, uint amountETH);
    function removeLiquidityWithPermit(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETHWithPermit(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountToken, uint amountETH);
    function swapExactTokensForTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapTokensForExactTokens(
        uint amountOut,
        uint amountInMax,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);
    function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
        external
        returns (uint[] memory amounts);
    function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        returns (uint[] memory amounts);
    function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);

    function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
    function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
    function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
    function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
    function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}

File 22 of 26 : IUniswapV2Router02.sol
pragma solidity >=0.6.2;

import "./IUniswapV2Router01.sol";

interface IUniswapV2Router02 is IUniswapV2Router01 {
    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountETH);
    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountETH);

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external payable;
    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
}

File 23 of 26 : ITheFactory.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/governance/IGovernor.sol";

interface ITheFactory {
    function proposeAgent(
        string memory name,
        string memory symbol,
        string memory tokenURI,
        uint8[] memory cores
        // ,
        // bytes32 tbaSalt,
        // address tbaImplementation,
        // uint32 daoVotingPeriod,
        // uint256 daoThreshold
    ) external returns (uint256);

    function withdraw(uint256 id) external;

    function totalAgents() external view returns (uint256);

    // function initFromToken(
    //     address tokenAddr,
    //     uint8[] memory cores,
    //     bytes32 tbaSalt,
    //     address tbaImplementation,
    //     uint32 daoVotingPeriod,
    //     uint256 daoThreshold,
    //     uint256 initialLP
    // ) external returns (uint256);

    // function executeTokenApplication(
    //     uint256 id,
    //     bool canStake
    // ) external;
}

File 24 of 26 : IAgentToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./IERC20Config.sol";
import "./IErrors.sol";

interface IAgentToken is
    IERC20,
    IERC20Config,
    IERC20Metadata,
    IErrors
{
    event AutoSwapThresholdUpdated(uint256 oldThreshold, uint256 newThreshold);

    event ExternalCallError(uint256 identifier);

    event InitialLiquidityAdded(
        uint256 tokenA,
        uint256 tokenB,
        uint256 lpToken
    );

    event LimitsUpdated(
        uint256 oldMaxTokensPerTransaction,
        uint256 newMaxTokensPerTransaction,
        uint256 oldMaxTokensPerWallet,
        uint256 newMaxTokensPerWallet
    );

    event LiquidityPoolCreated(address addedPool);

    event LiquidityPoolAdded(address addedPool);

    event LiquidityPoolRemoved(address removedPool);

    event ProjectTaxBasisPointsChanged(
        uint256 oldBuyBasisPoints,
        uint256 newBuyBasisPoints,
        uint256 oldSellBasisPoints,
        uint256 newSellBasisPoints
    );

    event RevenueAutoSwap();

    event ProjectTaxRecipientUpdated(address treasury);

    event ValidCallerAdded(bytes32 addedValidCaller);

    event ValidCallerRemoved(bytes32 removedValidCaller);

    /**
     * @dev function {addInitialLiquidity}
     *
     * Add initial liquidity to the uniswap pair
     *
     * @param lpOwner The recipient of LP tokens
     */
    function addInitialLiquidity(address lpOwner) external;

    /**
     * @dev function {isLiquidityPool}
     *
     * Return if an address is a liquidity pool
     *
     * @param queryAddress_ The address being queried
     * @return bool The address is / isn't a liquidity pool
     */
    function isLiquidityPool(
        address queryAddress_
    ) external view returns (bool);

    /**
     * @dev function {liquidityPools}
     *
     * Returns a list of all liquidity pools
     *
     * @return liquidityPools_ a list of all liquidity pools
     */
    function liquidityPools()
        external
        view
        returns (address[] memory liquidityPools_);

    /**
     * @dev function {addLiquidityPool} onlyOwner
     *
     * Allows the manager to add a liquidity pool to the pool enumerable set
     *
     * @param newLiquidityPool_ The address of the new liquidity pool
     */
    function addLiquidityPool(address newLiquidityPool_) external;

    /**
     * @dev function {removeLiquidityPool} onlyOwner
     *
     * Allows the manager to remove a liquidity pool
     *
     * @param removedLiquidityPool_ The address of the old removed liquidity pool
     */
    function removeLiquidityPool(address removedLiquidityPool_) external;

    /**
     * @dev function {isValidCaller}
     *
     * Return if an address is a valid caller
     *
     * @param queryHash_ The code hash being queried
     * @return bool The address is / isn't a valid caller
     */
    function isValidCaller(bytes32 queryHash_) external view returns (bool);

    /**
     * @dev function {validCallers}
     *
     * Returns a list of all valid caller code hashes
     *
     * @return validCallerHashes_ a list of all valid caller code hashes
     */
    function validCallers()
        external
        view
        returns (bytes32[] memory validCallerHashes_);

    /**
     * @dev function {addValidCaller} onlyOwner
     *
     * Allows the owner to add the hash of a valid caller
     *
     * @param newValidCallerHash_ The hash of the new valid caller
     */
    function addValidCaller(bytes32 newValidCallerHash_) external;

    /**
     * @dev function {removeValidCaller} onlyOwner
     *
     * Allows the owner to remove a valid caller
     *
     * @param removedValidCallerHash_ The hash of the old removed valid caller
     */
    function removeValidCaller(bytes32 removedValidCallerHash_) external;

    /**
     * @dev function {setProjectTaxRecipient} onlyOwner
     *
     * Allows the manager to set the project tax recipient address
     *
     * @param projectTaxRecipient_ New recipient address
     */
    function setProjectTaxRecipient(address projectTaxRecipient_) external;

    /**
     * @dev function {setSwapThresholdBasisPoints} onlyOwner
     *
     * Allows the manager to set the autoswap threshold
     *
     * @param swapThresholdBasisPoints_ New swap threshold in basis points
     */
    function setSwapThresholdBasisPoints(
        uint16 swapThresholdBasisPoints_
    ) external;

    /**
     * @dev function {setProjectTaxRates} onlyOwner
     *
     * Change the tax rates, subject to only ever decreasing
     *
     * @param newProjectBuyTaxBasisPoints_ The new buy tax rate
     * @param newProjectSellTaxBasisPoints_ The new sell tax rate
     */
    function setProjectTaxRates(
        uint16 newProjectBuyTaxBasisPoints_,
        uint16 newProjectSellTaxBasisPoints_
    ) external;

    /**
     * @dev totalBuyTaxBasisPoints
     *
     * Provide easy to view tax total:
     */
    function totalBuyTaxBasisPoints() external view returns (uint256);

    /**
     * @dev totalSellTaxBasisPoints
     *
     * Provide easy to view tax total:
     */
    function totalSellTaxBasisPoints() external view returns (uint256);

    /**
     * @dev distributeTaxTokens
     *
     * Allows the distribution of tax tokens to the designated recipient(s)
     *
     * As part of standard processing the tax token balance being above the threshold
     * will trigger an autoswap to ETH and distribution of this ETH to the designated
     * recipients. This is automatic and there is no need for user involvement.
     *
     * As part of this swap there are a number of calculations performed, particularly
     * if the tax balance is above MAX_SWAP_THRESHOLD_MULTIPLE.
     *
     * Testing indicates that these calculations are safe. But given the data / code
     * interactions it remains possible that some edge case set of scenarios may cause
     * an issue with these calculations.
     *
     * This method is therefore provided as a 'fallback' option to safely distribute
     * accumulated taxes from the contract, with a direct transfer of the ERC20 tokens
     * themselves.
     */
    function distributeTaxTokens() external;

    /**
     * @dev function {withdrawETH} onlyOwner
     *
     * A withdraw function to allow ETH to be withdrawn by the manager
     *
     * This contract should never hold ETH. The only envisaged scenario where
     * it might hold ETH is a failed autoswap where the uniswap swap has completed,
     * the recipient of ETH reverts, the contract then wraps to WETH and the
     * wrap to WETH fails.
     *
     * This feels unlikely. But, for safety, we include this method.
     *
     * @param amount_ The amount to withdraw
     */
    function withdrawETH(uint256 amount_) external;

    /**
     * @dev function {withdrawERC20} onlyOwner
     *
     * A withdraw function to allow ERC20s (except address(this)) to be withdrawn.
     *
     * This contract should never hold ERC20s other than tax tokens. The only envisaged
     * scenario where it might hold an ERC20 is a failed autoswap where the uniswap swap
     * has completed, the recipient of ETH reverts, the contract then wraps to WETH, the
     * wrap to WETH succeeds, BUT then the transfer of WETH fails.
     *
     * This feels even less likely than the scenario where ETH is held on the contract.
     * But, for safety, we include this method.
     *
     * @param token_ The ERC20 contract
     * @param amount_ The amount to withdraw
     */
    function withdrawERC20(address token_, uint256 amount_) external;

    /**
     * @dev Destroys a `value` amount of tokens from the caller.
     *
     * See {ERC20-_burn}.
     */
    function burn(uint256 value) external;

    /**
     * @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) external;

    /**
     * @dev {initializer}
     *
     * @param integrationAddresses_ The project owner, uniswap router, LP currency
     * @param baseParams_ configuration of this ERC20.
     * param supplyParams_ Supply configuration of this ERC20.
     * param taxParams_  Tax configuration of this ERC20
     * param taxParams_  Launch pool configuration of this ERC20
     * param lpSupply_  Initial supply to be minted for LP
     */
    function initialize(
        address[3] memory integrationAddresses_,
        bytes memory baseParams_,
        bytes memory supplyParams_,
        bytes memory taxParams_
    ) external;
}

File 25 of 26 : IERC20Config.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface IERC20Config {
  struct ERC20Config {
    bytes baseParameters;
    bytes supplyParameters;
    bytes taxParameters;
    bytes poolParameters;
  }

  struct ERC20BaseParameters {
    string name;
    string symbol;
  }

  struct ERC20SupplyParameters {
    uint256 maxSupply;
    uint256 lpSupply;
    uint256 vaultSupply;
    uint256 maxTokensPerWallet;
    uint256 maxTokensPerTxn;
    uint256 botProtectionDurationInSeconds;
    address vault;
  }

  struct ERC20TaxParameters {
    uint256 projectBuyTaxBasisPoints;
    uint256 projectSellTaxBasisPoints;
    uint256 taxSwapThresholdBasisPoints;
    address projectTaxRecipient;
  }
}

File 26 of 26 : IErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface IErrors {
  enum BondingCurveErrorType {
    OK, //                                                  No error
    INVALID_NUMITEMS, //                                    The numItem value is 0
    SPOT_PRICE_OVERFLOW //                                  The updated spot price doesn't fit into 128 bits
  }

  error AdapterParamsMustBeEmpty(); //                      The adapter parameters on this LZ call must be empty.

  error AdditionToPoolIsBelowPerTransactionMinimum(); //    The contribution amount is less than the minimum.

  error AdditionToPoolWouldExceedPoolCap(); //              This addition to the pool would exceed the pool cap.

  error AdditionToPoolWouldExceedPerAddressCap(); //        This addition to the pool would exceed the per address cap.

  error AddressAlreadySet(); //                             The address being set can only be set once, and is already non-0.

  error AllowanceDecreasedBelowZero(); //                   You cannot decrease the allowance below zero.

  error AlreadyInitialised(); //                            The contract is already initialised: it cannot be initialised twice!

  error ApprovalCallerNotOwnerNorApproved(); //             The caller must own the token or be an approved operator.

  error ApproveFromTheZeroAddress(); //                     Approval cannot be called from the zero address (indeed, how have you??).

  error ApproveToTheZeroAddress(); //                       Approval cannot be given to the zero address.

  error ApprovalQueryForNonexistentToken(); //              The token does not exist.

  error AuctionStatusIsNotEnded(); //                       Throw if the action required the auction to be closed, and it isn't.

  error AuctionStatusIsNotOpen(); //                        Throw if the action requires the auction to be open, and it isn't.

  error AuxCallFailed(
    address[] modules,
    uint256 value,
    bytes data,
    uint256 txGas
  ); //                                                     An auxilliary call from the drop factory failed.

  error BalanceMismatch(); //                               An error when comparing balance amounts.

  error BalanceQueryForZeroAddress(); //                    Cannot query the balance for the zero address.

  error BidMustBeBelowTheFloorWhenReducingQuantity(); //    Only bids that are below the floor can reduce the quantity of the bid.

  error BidMustBeBelowTheFloorForRefundDuringAuction(); //  Only bids that are below the floor can be refunded during the auction.

  error BondingCurveError(BondingCurveErrorType error); //  An error of the type specified has occured in bonding curve processing.

  error BurnExceedsBalance(); //                            The amount you have selected to burn exceeds the addresses balance.

  error BurnFromTheZeroAddress(); //                        Tokens cannot be burned from the zero address. (Also, how have you called this!?!)

  error CallerIsNotDepositBoxOwner(); //                    The caller is not the owner of the deposit box.

  error CallerIsNotFactory(); //                            The caller of this function must match the factory address in storage.

  error CallerIsNotFactoryOrProjectOwner(); //              The caller of this function must match the factory address OR project owner address.

  error CallerIsNotFactoryProjectOwnerOrPool(); //          The caller of this function must match the factory address, project owner or pool address.

  error CallerIsNotTheOwner(); //                           The caller is not the owner of this contract.

  error CallerIsNotTheManager(); //                         The caller is not the manager of this contract.

  error CallerMustBeLzApp(); //                             The caller must be an LZ application.

  error CallerIsNotPlatformAdmin(address caller); //        The caller of this function must be part of the platformAdmin group.

  error CallerIsNotSuperAdmin(address caller); //           The caller of this function must match the superAdmin address in storage.

  error CannotAddLiquidityOnCreateAndUseDRIPool(); //       Cannot use both liquidity added on create and a DRIPool in the same token.

  error CannotSetNewOwnerToTheZeroAddress(); //             You can't set the owner of this contract to the zero address (address(0)).

  error CannotSetToZeroAddress(); //                        The corresponding address cannot be set to the zero address (address(0)).

  error CannotSetNewManagerToTheZeroAddress(); //           Cannot transfer the manager to the zero address (address(0)).

  error CannotWithdrawThisToken(); //                       Cannot withdraw the specified token.

  error CanOnlyReduce(); //                                 The given operation can only reduce the value specified.

  error CollectionAlreadyRevealed(); //                     The collection is already revealed; you cannot call reveal again.

  error ContractIsDecommissioned(); //                      This contract is decommissioned!

  error ContractIsPaused(); //                              The call requires the contract to be unpaused, and it is paused.

  error ContractIsNotPaused(); //                           The call required the contract to be paused, and it is NOT paused.

  error DecreasedAllowanceBelowZero(); //                   The request would decrease the allowance below zero, and that is not allowed.

  error DestinationIsNotTrustedSource(); //                 The destination that is being called through LZ has not been set as trusted.

  error DeployerOnly(); //                                  This method can only be called by the deployer address.

  error DeploymentError(); //                               Error on deployment.

  error DepositBoxIsNotOpen(); //                           This action cannot complete as the deposit box is not open.

  error DriPoolAddressCannotBeAddressZero(); //             The Dri Pool address cannot be the zero address.

  error GasLimitIsTooLow(); //                              The gas limit for the LayerZero call is too low.

  error IncorrectConfirmationValue(); //                    You need to enter the right confirmation value to call this funtion (usually 69420).

  error IncorrectPayment(); //                              The function call did not include passing the correct payment.

  error InitialLiquidityAlreadyAdded(); //                  Initial liquidity has already been added. You can't do it again.

  error InitialLiquidityNotYetAdded(); //                   Initial liquidity needs to have been added for this to succedd.

  error InsufficientAllowance(); //                         There is not a high enough allowance for this operation.

  error InvalidAdapterParams(); //                          The current adapter params for LayerZero on this contract won't work :(.

  error InvalidAddress(); //                                An address being processed in the function is not valid.

  error InvalidEndpointCaller(); //                         The calling address is not a valid LZ endpoint. The LZ endpoint was set at contract creation
  //                                                        and cannot be altered after. Check the address LZ endpoint address on the contract.

  error InvalidMinGas(); //                                 The minimum gas setting for LZ in invalid.

  error InvalidOracleSignature(); //                        The signature provided with the contract call is not valid, either in format or signer.

  error InvalidPayload(); //                                The LZ payload is invalid

  error InvalidReceiver(); //                               The address used as a target for funds is not valid.

  error InvalidSourceSendingContract(); //                  The LZ message is being related from a source contract on another chain that is NOT trusted.

  error InvalidTotalShares(); //                            Total shares must equal 100 percent in basis points.

  error LimitsCanOnlyBeRaised(); //                          Limits are UP ONLY.

  error ListLengthMismatch(); //                            Two or more lists were compared and they did not match length.

  error LiquidityPoolMustBeAContractAddress(); //           Cannot add a non-contract as a liquidity pool.

  error LiquidityPoolCannotBeAddressZero(); //              Cannot add a liquidity pool from the zero address.

  error LPLockUpMustFitUint88(); //                         LP lockup is held in a uint88, so must fit.

  error NoTrustedPathRecord(); //                           LZ needs a trusted path record for this to work. What's that, you ask?

  error MachineAddressCannotBeAddressZero(); //             Cannot set the machine address to the zero address.

  error ManagerUnauthorizedAccount(); //                    The caller is not the pending manager.

  error MaxBidQuantityIs255(); //                           Validation: as we use a uint8 array to track bid positions the max bid quantity is 255.

  error MaxPublicMintAllowanceExceeded(
    uint256 requested,
    uint256 alreadyMinted,
    uint256 maxAllowance
  ); //                                                     The calling address has requested a quantity that would exceed the max allowance.

  error MaxSupplyTooHigh(); //                              Max supply must fit in a uint128.

  error MaxTokensPerWalletExceeded(); //                    The transfer would exceed the max tokens per wallet limit.

  error MaxTokensPerTxnExceeded(); //                       The transfer would exceed the max tokens per transaction limit.

  error MetadataIsLocked(); //                              The metadata on this contract is locked; it cannot be altered!

  error MinGasLimitNotSet(); //                             The minimum gas limit for LayerZero has not been set.

  error MintERC2309QuantityExceedsLimit(); //               The `quantity` minted with ERC2309 exceeds the safety limit.

  error MintingIsClosedForever(); //                        Minting is, as the error suggests, so over (and locked forever).

  error MintToZeroAddress(); //                             Cannot mint to the zero address.

  error MintZeroQuantity(); //                              The quantity of tokens minted must be more than zero.

  error NewBuyTaxBasisPointsExceedsMaximum(); //            Project owner trying to set the tax rate too high.

  error NewSellTaxBasisPointsExceedsMaximum(); //           Project owner trying to set the tax rate too high.

  error NoETHForLiquidityPair(); //                         No ETH has been provided for the liquidity pair.

  error TaxPeriodStillInForce(); //                         The minimum tax period has not yet expired.

  error NoPaymentDue(); //                                  No payment is due for this address.

  error NoRefundForCaller(); //                             Error thrown when the calling address has no refund owed.

  error NoStoredMessage(); //                               There is no stored message matching the passed parameters.

  error NothingToClaim(); //                                The calling address has nothing to claim.

  error NoTokenForLiquidityPair(); //                       There is no token to add to the LP.

  error OperationDidNotSucceed(); //                        The operation failed (vague much?).

  error OracleSignatureHasExpired(); //                     A signature has been provided but it is too old.

  error OwnershipNotInitializedForExtraData(); //           The `extraData` cannot be set on an uninitialized ownership slot.

  error OwnerQueryForNonexistentToken(); //                 The token does not exist.

  error CallerIsNotAdminNorFactory();   //                  The caller of this function must match the factory address or be an admin.

  error ParametersDoNotMatchSignedMessage(); //             The parameters passed with the signed message do not match the message itself.

  error ParamTooLargeStartDate(); //                        The passed parameter exceeds the var type max.

  error ParamTooLargeEndDate(); //                          The passed parameter exceeds the var type max.

  error ParamTooLargeMinETH(); //                           The passed parameter exceeds the var type max.

  error ParamTooLargePerAddressMax(); //                    The passed parameter exceeds the var type max.

  error ParamTooLargeVestingDays(); //                      The passed parameter exceeds the var type max.

  error ParamTooLargePoolSupply(); //                       The passed parameter exceeds the var type max.

  error ParamTooLargePoolPerTxnMinETH(); //                 The passed parameter exceeds the var type max.

  error PassedConfigDoesNotMatchApproved(); //              The config provided on the call does not match the approved config.

  error PauseCutOffHasPassed(); //                          The time period in which we can pause has passed; this contract can no longer be paused.

  error PaymentMustCoverPerMintFee(); //                    The payment passed must at least cover the per mint fee for the quantity requested.

  error PermitDidNotSucceed(); //                           The safeERC20 permit failed.

  error PlatformAdminCannotBeAddressZero(); //              We cannot use the zero address (address(0)) as a platformAdmin.

  error PlatformTreasuryCannotBeAddressZero(); //           The treasury address cannot be set to the zero address.

  error PoolIsAboveMinimum(); //                            You required the pool to be below the minimum, and it is not

  error PoolIsBelowMinimum(); //                            You required the pool to be above the minimum, and it is not

  error PoolPhaseIsClosed(); //                             The block.timestamp is either before the pool is open or after it is closed.

  error PoolPhaseIsNotAfter(); //                           The block.timestamp is either before or during the pool open phase.

  error PoolVestingNotYetComplete(); //                     Tokens in the pool are not yet vested.

  error ProjectOwnerCannotBeAddressZero(); //               The project owner has to be a non zero address.

  error ProofInvalid(); //                                  The provided proof is not valid with the provided arguments.

  error QuantityExceedsRemainingCollectionSupply(); //      The requested quantity would breach the collection supply.

  error QuantityExceedsRemainingPhaseSupply(); //           The requested quantity would breach the phase supply.

  error QuantityExceedsMaxPossibleCollectionSupply(); //    The requested quantity would breach the maximum trackable supply

  error ReferralIdAlreadyUsed(); //                         This referral ID has already been used; they are one use only.

  error RequestingMoreThanAvailableBalance(); //             The request exceeds the available balance.

  error RequestingMoreThanRemainingAllocation(
    uint256 previouslyMinted,
    uint256 requested,
    uint256 remainingAllocation
  ); //                                                     Number of tokens requested for this mint exceeds the remaining allocation (taking the
  //                                                        original allocation from the list and deducting minted tokens).

  error RoyaltyFeeWillExceedSalePrice(); //                 The ERC2981 royalty specified will exceed the sale price.

  error ShareTotalCannotBeZero(); //                        The total of all the shares cannot be nothing.

  error SliceOutOfBounds(); //                              The bytes slice operation was out of bounds.

  error SliceOverflow(); //                                 The bytes slice operation overlowed.

  error SuperAdminCannotBeAddressZero(); //                 The superAdmin cannot be the sero address (address(0)).

  error SupplyTotalMismatch(); //                           The sum of the team supply and lp supply does not match.

  error SupportWindowIsNotOpen(); //                        The project owner has not requested support within the support request expiry window.

  error TaxFreeAddressCannotBeAddressZero(); //             A tax free address cannot be address(0)

  error TemplateCannotBeAddressZero(); //                   The address for a template cannot be address zero (address(0)).

  error TemplateNotFound(); //                              There is no template that matches the passed template Id.

  error ThisMintIsClosed(); //                              It's over (well, this mint is, anyway).

  error TotalSharesMustMatchDenominator(); //               The total of all shares must equal the denominator value.

  error TransferAmountExceedsBalance(); //                  The transfer amount exceeds the accounts available balance.

  error TransferCallerNotOwnerNorApproved(); //             The caller must own the token or be an approved operator.

  error TransferFailed(); //                                The transfer has failed.

  error TransferFromIncorrectOwner(); //                    The token must be owned by `from`.

  error TransferToNonERC721ReceiverImplementer(); //        Cannot safely transfer to a contract that does not implement the ERC721Receiver interface.

  error TransferFromZeroAddress(); //                       Cannot transfer from the zero address. Indeed, this surely is impossible, and likely a waste to check??

  error TransferToZeroAddress(); //                         Cannot transfer to the zero address.

  error UnrecognisedVRFMode(); //                           Currently supported VRF modes are 0: chainlink and 1: arrng

  error URIQueryForNonexistentToken(); //                   The token does not exist.

  error ValueExceedsMaximum(); //                           The value sent exceeds the maximum allowed (super useful explanation huh?).

  error VRFCoordinatorCannotBeAddressZero(); //             The VRF coordinator cannot be the zero address (address(0)).
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "viaIR": true,
  "evmVersion": "paris",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract ABI

[{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"FailedDeployment","type":"error"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newThreshold","type":"uint256"}],"name":"ApplicationThresholdUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"}],"name":"NewApplication","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"virtualId","type":"uint256"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"lp","type":"address"}],"name":"NewPersona","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WITHDRAW_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allTokens","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allTradingTokens","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"applicationThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assetToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bool","name":"canStake","type":"bool"}],"name":"executeApplication","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"getApplication","outputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"string","name":"tokenURI","type":"string"},{"internalType":"enum TheFactory.ApplicationStatus","name":"status","type":"uint8"},{"internalType":"uint256","name":"withdrawableAmount","type":"uint256"},{"internalType":"address","name":"proposer","type":"address"},{"internalType":"uint8[]","name":"cores","type":"uint8[]"}],"internalType":"struct TheFactory.Application","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenImplementation_","type":"address"},{"internalType":"uint256","name":"nextId_","type":"uint256"},{"internalType":"address","name":"assetToken_","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maturityDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"string","name":"tokenURI","type":"string"},{"internalType":"uint8[]","name":"cores","type":"uint8[]"}],"name":"proposeAgent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newThreshold","type":"uint256"}],"name":"setApplicationThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newToken","type":"address"}],"name":"setAssetToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"setImplementations","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newDuration","type":"uint256"}],"name":"setMaturityDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTokenAdmin","type":"address"}],"name":"setTokenAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxSupply","type":"uint256"},{"internalType":"uint256","name":"lpSupply","type":"uint256"},{"internalType":"uint256","name":"vaultSupply","type":"uint256"},{"internalType":"uint256","name":"maxTokensPerWallet","type":"uint256"},{"internalType":"uint256","name":"maxTokensPerTxn","type":"uint256"},{"internalType":"uint256","name":"botProtectionDurationInSeconds","type":"uint256"},{"internalType":"address","name":"vault","type":"address"}],"name":"setTokenSupplyParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"projectBuyTaxBasisPoints","type":"uint256"},{"internalType":"uint256","name":"projectSellTaxBasisPoints","type":"uint256"},{"internalType":"uint256","name":"taxSwapThresholdBasisPoints","type":"uint256"},{"internalType":"address","name":"projectTaxRecipient","type":"address"}],"name":"setTokenTaxParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"router","type":"address"}],"name":"setUniswapRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAgents","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60808060405234601f5760ff196001541660015561292590816100258239f35b600080fdfe608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a71461223857508063063513b71461221a5780631083f761146121f15780631f2f4bfd14611a7c578063248a9ca314611a4657806326bde5aa14611a065780632a7d4a1f146118665780632e1a7d4d1461175d5780632f2ff15d1461171c5780632f3a3d5d146116f357806336568abe146116ae5780633f4ba83a146116465780635c975abb146116235780635ca3cedf1461147d578063634282af14611403578063820e34d214610c6f5780638456cb5914610c1557806391d1485414610bcd5780639352dace14610b8d578063a217fddf14610b71578063aa3d000a14610501578063bd1cf258146104b3578063bea9849e14610473578063c350a1b5146102e0578063c5053712146102c2578063d547741f14610278578063d739ac2914610255578063ddf4427514610237578063e02023a1146101fc578063e887b1cc146101b85763f74575941461017657600080fd5b346101b55760203660031901126101b55761018f6122ce565b6101976125c3565b60018060a01b03166001600160601b0360a01b600c541617600c5580f35b80fd5b50346101b55760203660031901126101b55760043590600a548210156101b55760206101e3836122ff565b905460405160039290921b1c6001600160a01b03168152f35b50346101b557806003193601126101b55760206040517f5d8e12c39142ff96d79d04d15d1ba1269e4fe57bb9d26f43523628b34ba108ec8152f35b50346101b557806003193601126101b5576020600454604051908152f35b50346101b55760203660031901126101b55761026f6125c3565b60043560075580f35b50346101b55760403660031901126101b5576102be6004356102986122e9565b906102b96102b482600052600060205260016040600020015490565b612616565b6127c9565b5080f35b50346101b557806003193601126101b5576020600554604051908152f35b50346101b55760603660031901126101b5576102fa6122ce565b6044356001600160a01b0381169081900361046f576000805160206128d0833981519152549160ff8360401c1615926001600160401b03811680159081610467575b600114908161045d575b159081610454575b506104455767ffffffffffffffff1981166001176000805160206128d08339815191525583610418575b5060018060a01b03166001600160601b0360a01b60035416176003556001600160601b0360a01b60065416176006556024356002556103b63361268c565b506103be5780f35b68ff0000000000000000196000805160206128d083398151915254166000805160206128d0833981519152557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a180f35b68ffffffffffffffffff191668010000000000000001176000805160206128d08339815191525538610378565b63f92ee8a960e01b8552600485fd5b9050153861034e565b303b159150610346565b85915061033c565b8280fd5b50346101b55760203660031901126101b55761048d6122ce565b6104956125c3565b60018060a01b03166001600160601b0360a01b600b541617600b5580f35b50346101b55760203660031901126101b5577fcfa33021ab0175831433b2f3bd8eeb24a22f5ae53ca0e660a246811754f9e34a60206004356104f36125c3565b80600455604051908152a180f35b50346101b55760403660031901126101b55760043590602435801515036101b557600160095461053460ff8216156124ff565b60ff191617600955818152600860205260408120600501546001600160a01b031633148015610b32575b6105679061253c565b604051918183600d549161057a836123ef565b8083529260018116908115610b135750600114610ab5575b61059e92500384612361565b808252600860205260ff6003604084200154166003811015610aa1576105c49015612577565b600c546001600160a01b031615610a665781526008602052604081206004810192828454945560038201600160ff19825416179055600161062e60405193610617856106108184612429565b0386612361565b6106276040518094819301612429565b0382612361565b600354608881901c62ffffff16763d602d80600a3d3981f3363d3d373d3d3d363d7300000017855260781b6effffffffffffffffffffffffffffff19166e5af43d82803e903d91602b57fd5bf3176020526037600985f06001600160a01b038116939092908415610a575760405192606084018481106001600160401b03821117610a435791610718610726926107069460405260018060a01b03600c5416875260018060a01b03600b5416602088015260018060a01b0360065416604088015260405194859360406020860152606085019061228d565b838103601f190160408501529061228d565b03601f198101835282612361565b843b1561096a57604051634258efa960e11b81529286928492909184600485015b60038210610a1d575050509061076b61077d9260c0606486015260c485019061228d565b8381036003190160848501529061228d565b8181036003190160a4830152600e548391610797826123ef565b91828252846001821691826000146109ff5750506001146109a1575b50508190038183875af1801561096e5761098d575b50600a54600160401b811015610979578060016107e89201600a556122ff565b81546001600160a01b0360039290921b91821b19169084901b17905560405163d6efd7c360e01b81528381600481865afa90811561096e5784916108bd575b5051156108a9576006549293849361084892906001600160a01b0316612651565b803b156108a657818091602460405180948193631672aef960e21b83523060048401525af1801561089b57610886575b5060ff196009541660095580f35b8161089091612361565b6101b5578038610878565b6040513d84823e3d90fd5b50fd5b634e487b7160e01b83526032600452602483fd5b90503d8085833e6108ce8183612361565b810190602081830312610966578051906001600160401b03821161096a57019080601f8301121561096657815190610905826123d8565b926109136040519485612361565b82845260208085019360051b82010191821161096257602001915b81831061093e5750505038610827565b82516001600160a01b038116810361095e5781526020928301920161092e565b8780fd5b8680fd5b8480fd5b8580fd5b6040513d86823e3d90fd5b634e487b7160e01b84526041600452602484fd5b8361099a91949294612361565b91386107c8565b600e8552849250907fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd5b8184106109df5750500160200181386107b3565b6001919550602092945080548385870101520191019091879385936109cb565b909450602093915060ff191683830152151560051b010190386107b3565b82516001600160a01b031681528a96508795506020928301926001929092019101610747565b634e487b7160e01b88526041600452602488fd5b63b06ebf3d60e01b8652600486fd5b60405162461bcd60e51b8152602060048201526013602482015272151bdad95b8818591b5a5b881b9bdd081cd95d606a1b6044820152606490fd5b634e487b7160e01b83526021600452602483fd5b50600d84529083907fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb55b818310610af757505090602061059e92820101610592565b6020919350806001915483858a01015201910190918592610adf565b6020925061059e94915060ff191682840152151560051b820101610592565b507f5d8e12c39142ff96d79d04d15d1ba1269e4fe57bb9d26f43523628b34ba108ec81526020818152604080832033845290915281205460ff1661055e565b50346101b557806003193601126101b557602090604051908152f35b50346101b55760203660031901126101b557610ba76122ce565b610baf6125c3565b60018060a01b03166001600160601b0360a01b600354161760035580f35b50346101b55760403660031901126101b55760ff6040602092610bee6122e9565b60043582528185528282206001600160a01b03909116825284522054604051911615158152f35b50346101b557806003193601126101b557610c2e6125c3565b610c3661284b565b600160ff19815416176001557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a180f35b50346101b55760803660031901126101b5576004356001600160401b0381116113ff57610ca0903690600401612382565b6024356001600160401b03811161046f57610cbf903690600401612382565b6044356001600160401b0381116113d957610cde903690600401612382565b92606435926001600160401b0384116113ff57366023850112156113ff578360040135610d0a816123d8565b94610d186040519687612361565b8186526024602087019260051b8201019036821161096657602401915b8183106113e557505050610d4761284b565b6006546040516370a0823160e01b81523360048201526001600160a01b0390911690602081602481855afa90811561096e5784916113af575b5060045480911061136a57604051636eb1769f60e11b8152336004820152306024820152602081604481865afa90811561135f57908291869161132a575b50106112da5785511561129c57610e0591604051916323b872dd60e01b6020840152336024840152306044840152606483015260648252610e00608483612361565b612868565b600254926000198414611288576001840160025560045460405192610e2984612330565b8352602083019182526040830196875260608301968488526080840191825260a084019233845260c0850197885286865260086020526040862094518051906001600160401b038211610a4357610e8a82610e8489546123ef565b896124c3565b602090601f831160011461122557610eba9291899183611140575b50508160011b916000199060031b1c19161790565b85555b51805160018601916001600160401b038211610a4357610ee782610ee185546123ef565b856124c3565b602090601f83116001146111c257610f1692918991836111405750508160011b916000199060031b1c19161790565b90555b51805160028501916001600160401b0382116111ae57610f3d82610ee185546123ef565b602090601f831160011461114b57610f6c92918891836111405750508160011b916000199060031b1c19161790565b90555b60038301965196600388101561112c57849596976006955060ff80198354169116179055516004830155600582019060018060a01b039051166001600160601b0360a01b8254161790550192518051906001600160401b03821161111857600160401b82116111185760209085548387558084106110cc575b5001938252602082208160051c91835b83811061108d5750601f198116900380611041575b6020857f0ff47c4a3dc48719ecfd1876116e80d7d76ec7cb67248ae49449f9104747af2982604051838152a1604051908152f35b9483955b80871061105d5750506020945001553880808061100d565b909360206110826001928960ff895116919060ff809160031b9316831b921b19161790565b950196019590611045565b84855b602081106110a5575083820155600101610ff8565b885190989160019160209160ff60038d901b81811b199092169216901b1792019801611090565b6110f690878652838620601f80870160051c820192818816806110fc575b500160051c01906124ac565b38610fe8565b600019850190815490600019908a0360031b1c169055386110ea565b634e487b7160e01b83526041600452602483fd5b634e487b7160e01b85526021600452602485fd5b015190503880610ea5565b8388528188209190601f198416895b818110611196575090846001959493921061117d575b505050811b019055610f6f565b015160001960f88460031b161c19169055388080611170565b9293602060018192878601518155019501930161115a565b634e487b7160e01b87526041600452602487fd5b8389528189209190601f1984168a5b81811061120d57509084600195949392106111f4575b505050811b019055610f19565b015160001960f88460031b161c191690553880806111e7565b929360206001819287860151815501950193016111d1565b8789528189209190601f1984168a5b8181106112705750908460019594939210611257575b505050811b018555610ebd565b015160001960f88460031b161c1916905538808061124a565b92936020600181928786015181550195019301611234565b634e487b7160e01b83526011600452602483fd5b60405162461bcd60e51b815260206004820152601660248201527510dbdc995cc81b5d5cdd081899481c1c9bdd9a59195960521b6044820152606490fd5b60405162461bcd60e51b815260206004820152602260248201527f496e73756666696369656e7420617373657420746f6b656e20616c6c6f77616e604482015261636560f01b6064820152608490fd5b9150506020813d602011611357575b8161134660209383612361565b810103126109665781905138610dbe565b3d9150611339565b6040513d87823e3d90fd5b60405162461bcd60e51b815260206004820152601860248201527f496e73756666696369656e7420617373657420746f6b656e00000000000000006044820152606490fd5b90506020813d6020116113dd575b816113ca60209383612361565b810103126113d9575138610d80565b8380fd5b3d91506113bd565b823560ff8116810361096a57815260209283019201610d35565b5080fd5b50346101b55760203660031901126101b557600435906005548210156101b55760055482101561146957600590527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db001546040516001600160a01b039091168152602090f35b634e487b7160e01b81526032600452602490fd5b50346101b55760803660031901126101b5576064356001600160a01b03811691908290036101b5576114ad6125c3565b604051916004356020840152602435604084015260443560608401526080830152608082526114dd60a083612361565b81516001600160401b03811161160f576114f8600e546123ef565b601f81116115b6575b50602092601f8211600114611538578293829161153294926111405750508160011b916000199060031b1c19161790565b600e5580f35b600e8352601f198216937fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd91845b86811061159e5750836001959610611585575b505050811b01600e5580f35b015160001960f88460031b161c19169055388080611579565b91926020600181928685015181550194019201611566565b600e83526115ff907fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd601f840160051c81019160208510611605575b601f0160051c01906124ac565b38611501565b90915081906115f2565b634e487b7160e01b82526041600452602482fd5b50346101b557806003193601126101b557602060ff600154166040519015158152f35b50346101b557806003193601126101b55761165f6125c3565b60015460ff81161561169f5760ff19166001557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a180f35b638dfc202b60e01b8252600482fd5b50346101b55760403660031901126101b5576116c86122e9565b336001600160a01b038216036116e4576102be906004356127c9565b63334bd91960e11b8252600482fd5b50346101b557806003193601126101b5576003546040516001600160a01b039091168152602090f35b50346101b55760403660031901126101b5576102be60043561173c6122e9565b906117586102b482600052600060205260016040600020015490565b61273e565b50346101b55760203660031901126101b557600160095461178160ff8216156124ff565b60ff1916176009556004358152600860205260408120906005820160018060a01b0381541633148015611827575b6117b89061253c565b600383019060ff82541660038110156118135761180693946117dc60049215612577565b01805490859055825460ff191660021790925560065490546001600160a01b039081169116612651565b60ff196009541660095580f35b634e487b7160e01b84526021600452602484fd5b507f5d8e12c39142ff96d79d04d15d1ba1269e4fe57bb9d26f43523628b34ba108ec82526020828152604080842033855290915282205460ff166117af565b50346101b55760e03660031901126101b55760c4356001600160a01b03811691908290036101b5576118966125c3565b60405191600435602084015260243560408401526044356060840152606435608084015260843560a084015260a43560c084015260e083015260e082526118df61010083612361565b81516001600160401b03811161160f576118fa600d546123ef565b601f81116119b8575b50602092601f821160011461193a578293829161193494926111405750508160011b916000199060031b1c19161790565b600d5580f35b600d8352601f198216937fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb591845b8681106119a05750836001959610611987575b505050811b01600d5580f35b015160001960f88460031b161c1916905538808061197b565b91926020600181928685015181550194019201611968565b600d8352611a00907fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb5601f840160051c8101916020851061160557601f0160051c01906124ac565b38611903565b50346101b55760203660031901126101b557611a206122ce565b611a286125c3565b60018060a01b03166001600160601b0360a01b600654161760065580f35b50346101b55760203660031901126101b5576020611a74600435600052600060205260016040600020015490565b604051908152f35b50346101b55760203660031901126101b557606060c0604051611a9e81612330565b82815282602082015282604082015283838201528360808201528360a0820152015260043581526008602052604081209060405191611adc83612330565b604051611aed816106278185612429565b8352604051611b03816106278160018601612429565b6020840190815260405191611b2683611b1f8160028501612429565b0384612361565b6040850192835260ff6003820154169260608601936003811015611d6257845260048201549060808701918252600660018060a01b036005850154169360a08901948552019360405180958691602082549182815201918a5260208a20908a915b81601f8401106120495792611ca992611ce19592611cf49897955491818110612035575b81811061201e575b818110612007575b818110611ff0575b818110611fda575b818110611fc3575b818110611fac575b818110611f95575b818110611f7e575b818110611f67575b818110611f50575b818110611f39575b818110611f22575b818110611f0b575b818110611ef4575b818110611edd575b818110611ec6575b818110611eaf575b818110611e98575b818110611e81575b818110611e6a575b818110611e53575b818110611e3c575b818110611e25575b818110611e0e575b818110611df7575b818110611de0575b818110611dc9575b818110611db2575b818110611d9b575b818110611d84575b10611d76575b500388612361565b60c08a01968752611cce6040519a60208c525160e060208d01526101008c019061228d565b90518a8203601f190160408c015261228d565b9051888203601f190160608a015261228d565b93516003811015611d625760808701525160a0860152516001600160a01b031660c085015251838203601f190160e085015280518083528493602093840193909201915b818110611d46575050500390f35b825160ff16845285945060209384019390920191600101611d38565b634e487b7160e01b86526021600452602486fd5b60f81c815260200138611ca1565b92602060019160ff8560f01c168152019301611c9b565b92602060019160ff8560e81c168152019301611c93565b92602060019160ff8560e01c168152019301611c8b565b92602060019160ff8560d81c168152019301611c83565b92602060019160ff8560d01c168152019301611c7b565b92602060019160ff8560c81c168152019301611c73565b92602060019160ff8560c01c168152019301611c6b565b92602060019160ff8560b81c168152019301611c63565b92602060019160ff8560b01c168152019301611c5b565b92602060019160ff8560a81c168152019301611c53565b92602060019160ff8560a01c168152019301611c4b565b92602060019160ff8560981c168152019301611c43565b92602060019160ff8560901c168152019301611c3b565b92602060019160ff8560881c168152019301611c33565b92602060019160ff8560801c168152019301611c2b565b92602060019160ff8560781c168152019301611c23565b92602060019160ff8560701c168152019301611c1b565b92602060019160ff8560681c168152019301611c13565b92602060019160ff8560601c168152019301611c0b565b92602060019160ff8560581c168152019301611c03565b92602060019160ff8560501c168152019301611bfb565b92602060019160ff8560481c168152019301611bf3565b92602060019160ff8560401c168152019301611beb565b92602060019160ff8560381c168152019301611be3565b92602060019160ff8560301c168152019301611bdb565b92602060019160ff8560281c168152019301611bd3565b92602060019160ff85831c168152019301611bcb565b92602060019160ff8560181c168152019301611bc3565b92602060019160ff8560101c168152019301611bbb565b92602060019160ff8560081c168152019301611bb3565b92602060019160ff85168152019301611bab565b935090916001610400602092865460ff8116825260ff8160081c168583015260ff8160101c16604083015260ff8160181c16606083015260ff81861c16608083015260ff8160281c1660a083015260ff8160301c1660c083015260ff8160381c1660e083015260ff8160401c1661010083015260ff8160481c1661012083015260ff8160501c1661014083015260ff8160581c1661016083015260ff8160601c1661018083015260ff8160681c166101a083015260ff8160701c166101c083015260ff8160781c166101e083015260ff8160801c1661020083015260ff8160881c1661022083015260ff8160901c1661024083015260ff8160981c1661026083015260ff8160a01c1661028083015260ff8160a81c166102a083015260ff8160b01c166102c083015260ff8160b81c166102e083015260ff8160c01c1661030083015260ff8160c81c1661032083015260ff8160d01c1661034083015260ff8160d81c1661036083015260ff8160e01c1661038083015260ff8160e81c166103a083015260ff8160f01c166103c083015260f81c6103e0820152019401920190889392611b87565b50346101b557806003193601126101b5576006546040516001600160a01b039091168152602090f35b50346101b557806003193601126101b5576020600754604051908152f35b9050346113ff5760203660031901126113ff5760043563ffffffff60e01b811680910361046f5760209250637965db0b60e01b811490811561227c575b5015158152f35b6301ffc9a760e01b14905038612275565b919082519283825260005b8481106122b9575050826000602080949584010152601f8019910116010190565b80602080928401015182828601015201612298565b600435906001600160a01b03821682036122e457565b600080fd5b602435906001600160a01b03821682036122e457565b600a5481101561231a57600a60005260206000200190600090565b634e487b7160e01b600052603260045260246000fd5b60e081019081106001600160401b0382111761234b57604052565b634e487b7160e01b600052604160045260246000fd5b90601f801991011681019081106001600160401b0382111761234b57604052565b81601f820112156122e4578035906001600160401b03821161234b57604051926123b6601f8401601f191660200185612361565b828452602083830101116122e457816000926020809301838601378301015290565b6001600160401b03811161234b5760051b60200190565b90600182811c9216801561241f575b602083101461240957565b634e487b7160e01b600052602260045260246000fd5b91607f16916123fe565b60009291815491612439836123ef565b808352926001811690811561248f575060011461245557505050565b60009081526020812093945091925b838310612475575060209250010190565b600181602092949394548385870101520191019190612464565b915050602093945060ff929192191683830152151560051b010190565b8181106124b7575050565b600081556001016124ac565b9190601f81116124d257505050565b6124fd926000526020600020906020601f840160051c8301931061160557601f0160051c01906124ac565b565b1561250657565b60405162461bcd60e51b815260206004820152600e60248201526d31b0b73737ba103932b2b73a32b960911b6044820152606490fd5b1561254357565b60405162461bcd60e51b815260206004820152600c60248201526b2737ba10383937b837b9b2b960a11b6044820152606490fd5b1561257e57565b60405162461bcd60e51b815260206004820152601960248201527f4170706c69636174696f6e206973206e6f7420616374697665000000000000006044820152606490fd5b3360009081527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5602052604090205460ff16156125fc57565b63e2517d3f60e01b60005233600452600060245260446000fd5b60008181526020818152604080832033845290915290205460ff16156126395750565b63e2517d3f60e01b6000523360045260245260446000fd5b60405163a9059cbb60e01b60208201526001600160a01b0390921660248301526044808301939093529181526124fd91610e00606483612361565b6001600160a01b03811660009081527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5602052604090205460ff16612738576001600160a01b031660008181527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb560205260408120805460ff191660011790553391907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d8180a4600190565b50600090565b6000818152602081815260408083206001600160a01b038616845290915290205460ff166127c2576000818152602081815260408083206001600160a01b0395909516808452949091528120805460ff19166001179055339291907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9080a4600190565b5050600090565b6000818152602081815260408083206001600160a01b038616845290915290205460ff16156127c2576000818152602081815260408083206001600160a01b0395909516808452949091528120805460ff19169055339291907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9080a4600190565b60ff6001541661285757565b63d93c066560e01b60005260046000fd5b906000602091828151910182855af1156128c3576000513d6128ba57506001600160a01b0381163b155b6128995750565b635274afe760e01b60009081526001600160a01b0391909116600452602490fd5b60011415612892565b6040513d6000823e3d90fdfef0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00a264697066735822122092d21f722413106e34835bf19607b553546784a20a8755d5d9dd69dcab773aa164736f6c634300081c0033

Deployed Bytecode

0x608080604052600436101561001357600080fd5b600090813560e01c90816301ffc9a71461223857508063063513b71461221a5780631083f761146121f15780631f2f4bfd14611a7c578063248a9ca314611a4657806326bde5aa14611a065780632a7d4a1f146118665780632e1a7d4d1461175d5780632f2ff15d1461171c5780632f3a3d5d146116f357806336568abe146116ae5780633f4ba83a146116465780635c975abb146116235780635ca3cedf1461147d578063634282af14611403578063820e34d214610c6f5780638456cb5914610c1557806391d1485414610bcd5780639352dace14610b8d578063a217fddf14610b71578063aa3d000a14610501578063bd1cf258146104b3578063bea9849e14610473578063c350a1b5146102e0578063c5053712146102c2578063d547741f14610278578063d739ac2914610255578063ddf4427514610237578063e02023a1146101fc578063e887b1cc146101b85763f74575941461017657600080fd5b346101b55760203660031901126101b55761018f6122ce565b6101976125c3565b60018060a01b03166001600160601b0360a01b600c541617600c5580f35b80fd5b50346101b55760203660031901126101b55760043590600a548210156101b55760206101e3836122ff565b905460405160039290921b1c6001600160a01b03168152f35b50346101b557806003193601126101b55760206040517f5d8e12c39142ff96d79d04d15d1ba1269e4fe57bb9d26f43523628b34ba108ec8152f35b50346101b557806003193601126101b5576020600454604051908152f35b50346101b55760203660031901126101b55761026f6125c3565b60043560075580f35b50346101b55760403660031901126101b5576102be6004356102986122e9565b906102b96102b482600052600060205260016040600020015490565b612616565b6127c9565b5080f35b50346101b557806003193601126101b5576020600554604051908152f35b50346101b55760603660031901126101b5576102fa6122ce565b6044356001600160a01b0381169081900361046f576000805160206128d0833981519152549160ff8360401c1615926001600160401b03811680159081610467575b600114908161045d575b159081610454575b506104455767ffffffffffffffff1981166001176000805160206128d08339815191525583610418575b5060018060a01b03166001600160601b0360a01b60035416176003556001600160601b0360a01b60065416176006556024356002556103b63361268c565b506103be5780f35b68ff0000000000000000196000805160206128d083398151915254166000805160206128d0833981519152557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a180f35b68ffffffffffffffffff191668010000000000000001176000805160206128d08339815191525538610378565b63f92ee8a960e01b8552600485fd5b9050153861034e565b303b159150610346565b85915061033c565b8280fd5b50346101b55760203660031901126101b55761048d6122ce565b6104956125c3565b60018060a01b03166001600160601b0360a01b600b541617600b5580f35b50346101b55760203660031901126101b5577fcfa33021ab0175831433b2f3bd8eeb24a22f5ae53ca0e660a246811754f9e34a60206004356104f36125c3565b80600455604051908152a180f35b50346101b55760403660031901126101b55760043590602435801515036101b557600160095461053460ff8216156124ff565b60ff191617600955818152600860205260408120600501546001600160a01b031633148015610b32575b6105679061253c565b604051918183600d549161057a836123ef565b8083529260018116908115610b135750600114610ab5575b61059e92500384612361565b808252600860205260ff6003604084200154166003811015610aa1576105c49015612577565b600c546001600160a01b031615610a665781526008602052604081206004810192828454945560038201600160ff19825416179055600161062e60405193610617856106108184612429565b0386612361565b6106276040518094819301612429565b0382612361565b600354608881901c62ffffff16763d602d80600a3d3981f3363d3d373d3d3d363d7300000017855260781b6effffffffffffffffffffffffffffff19166e5af43d82803e903d91602b57fd5bf3176020526037600985f06001600160a01b038116939092908415610a575760405192606084018481106001600160401b03821117610a435791610718610726926107069460405260018060a01b03600c5416875260018060a01b03600b5416602088015260018060a01b0360065416604088015260405194859360406020860152606085019061228d565b838103601f190160408501529061228d565b03601f198101835282612361565b843b1561096a57604051634258efa960e11b81529286928492909184600485015b60038210610a1d575050509061076b61077d9260c0606486015260c485019061228d565b8381036003190160848501529061228d565b8181036003190160a4830152600e548391610797826123ef565b91828252846001821691826000146109ff5750506001146109a1575b50508190038183875af1801561096e5761098d575b50600a54600160401b811015610979578060016107e89201600a556122ff565b81546001600160a01b0360039290921b91821b19169084901b17905560405163d6efd7c360e01b81528381600481865afa90811561096e5784916108bd575b5051156108a9576006549293849361084892906001600160a01b0316612651565b803b156108a657818091602460405180948193631672aef960e21b83523060048401525af1801561089b57610886575b5060ff196009541660095580f35b8161089091612361565b6101b5578038610878565b6040513d84823e3d90fd5b50fd5b634e487b7160e01b83526032600452602483fd5b90503d8085833e6108ce8183612361565b810190602081830312610966578051906001600160401b03821161096a57019080601f8301121561096657815190610905826123d8565b926109136040519485612361565b82845260208085019360051b82010191821161096257602001915b81831061093e5750505038610827565b82516001600160a01b038116810361095e5781526020928301920161092e565b8780fd5b8680fd5b8480fd5b8580fd5b6040513d86823e3d90fd5b634e487b7160e01b84526041600452602484fd5b8361099a91949294612361565b91386107c8565b600e8552849250907fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd5b8184106109df5750500160200181386107b3565b6001919550602092945080548385870101520191019091879385936109cb565b909450602093915060ff191683830152151560051b010190386107b3565b82516001600160a01b031681528a96508795506020928301926001929092019101610747565b634e487b7160e01b88526041600452602488fd5b63b06ebf3d60e01b8652600486fd5b60405162461bcd60e51b8152602060048201526013602482015272151bdad95b8818591b5a5b881b9bdd081cd95d606a1b6044820152606490fd5b634e487b7160e01b83526021600452602483fd5b50600d84529083907fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb55b818310610af757505090602061059e92820101610592565b6020919350806001915483858a01015201910190918592610adf565b6020925061059e94915060ff191682840152151560051b820101610592565b507f5d8e12c39142ff96d79d04d15d1ba1269e4fe57bb9d26f43523628b34ba108ec81526020818152604080832033845290915281205460ff1661055e565b50346101b557806003193601126101b557602090604051908152f35b50346101b55760203660031901126101b557610ba76122ce565b610baf6125c3565b60018060a01b03166001600160601b0360a01b600354161760035580f35b50346101b55760403660031901126101b55760ff6040602092610bee6122e9565b60043582528185528282206001600160a01b03909116825284522054604051911615158152f35b50346101b557806003193601126101b557610c2e6125c3565b610c3661284b565b600160ff19815416176001557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a180f35b50346101b55760803660031901126101b5576004356001600160401b0381116113ff57610ca0903690600401612382565b6024356001600160401b03811161046f57610cbf903690600401612382565b6044356001600160401b0381116113d957610cde903690600401612382565b92606435926001600160401b0384116113ff57366023850112156113ff578360040135610d0a816123d8565b94610d186040519687612361565b8186526024602087019260051b8201019036821161096657602401915b8183106113e557505050610d4761284b565b6006546040516370a0823160e01b81523360048201526001600160a01b0390911690602081602481855afa90811561096e5784916113af575b5060045480911061136a57604051636eb1769f60e11b8152336004820152306024820152602081604481865afa90811561135f57908291869161132a575b50106112da5785511561129c57610e0591604051916323b872dd60e01b6020840152336024840152306044840152606483015260648252610e00608483612361565b612868565b600254926000198414611288576001840160025560045460405192610e2984612330565b8352602083019182526040830196875260608301968488526080840191825260a084019233845260c0850197885286865260086020526040862094518051906001600160401b038211610a4357610e8a82610e8489546123ef565b896124c3565b602090601f831160011461122557610eba9291899183611140575b50508160011b916000199060031b1c19161790565b85555b51805160018601916001600160401b038211610a4357610ee782610ee185546123ef565b856124c3565b602090601f83116001146111c257610f1692918991836111405750508160011b916000199060031b1c19161790565b90555b51805160028501916001600160401b0382116111ae57610f3d82610ee185546123ef565b602090601f831160011461114b57610f6c92918891836111405750508160011b916000199060031b1c19161790565b90555b60038301965196600388101561112c57849596976006955060ff80198354169116179055516004830155600582019060018060a01b039051166001600160601b0360a01b8254161790550192518051906001600160401b03821161111857600160401b82116111185760209085548387558084106110cc575b5001938252602082208160051c91835b83811061108d5750601f198116900380611041575b6020857f0ff47c4a3dc48719ecfd1876116e80d7d76ec7cb67248ae49449f9104747af2982604051838152a1604051908152f35b9483955b80871061105d5750506020945001553880808061100d565b909360206110826001928960ff895116919060ff809160031b9316831b921b19161790565b950196019590611045565b84855b602081106110a5575083820155600101610ff8565b885190989160019160209160ff60038d901b81811b199092169216901b1792019801611090565b6110f690878652838620601f80870160051c820192818816806110fc575b500160051c01906124ac565b38610fe8565b600019850190815490600019908a0360031b1c169055386110ea565b634e487b7160e01b83526041600452602483fd5b634e487b7160e01b85526021600452602485fd5b015190503880610ea5565b8388528188209190601f198416895b818110611196575090846001959493921061117d575b505050811b019055610f6f565b015160001960f88460031b161c19169055388080611170565b9293602060018192878601518155019501930161115a565b634e487b7160e01b87526041600452602487fd5b8389528189209190601f1984168a5b81811061120d57509084600195949392106111f4575b505050811b019055610f19565b015160001960f88460031b161c191690553880806111e7565b929360206001819287860151815501950193016111d1565b8789528189209190601f1984168a5b8181106112705750908460019594939210611257575b505050811b018555610ebd565b015160001960f88460031b161c1916905538808061124a565b92936020600181928786015181550195019301611234565b634e487b7160e01b83526011600452602483fd5b60405162461bcd60e51b815260206004820152601660248201527510dbdc995cc81b5d5cdd081899481c1c9bdd9a59195960521b6044820152606490fd5b60405162461bcd60e51b815260206004820152602260248201527f496e73756666696369656e7420617373657420746f6b656e20616c6c6f77616e604482015261636560f01b6064820152608490fd5b9150506020813d602011611357575b8161134660209383612361565b810103126109665781905138610dbe565b3d9150611339565b6040513d87823e3d90fd5b60405162461bcd60e51b815260206004820152601860248201527f496e73756666696369656e7420617373657420746f6b656e00000000000000006044820152606490fd5b90506020813d6020116113dd575b816113ca60209383612361565b810103126113d9575138610d80565b8380fd5b3d91506113bd565b823560ff8116810361096a57815260209283019201610d35565b5080fd5b50346101b55760203660031901126101b557600435906005548210156101b55760055482101561146957600590527f036b6384b5eca791c62761152d0c79bb0604c104a5fb6f4eb0703f3154bb3db001546040516001600160a01b039091168152602090f35b634e487b7160e01b81526032600452602490fd5b50346101b55760803660031901126101b5576064356001600160a01b03811691908290036101b5576114ad6125c3565b604051916004356020840152602435604084015260443560608401526080830152608082526114dd60a083612361565b81516001600160401b03811161160f576114f8600e546123ef565b601f81116115b6575b50602092601f8211600114611538578293829161153294926111405750508160011b916000199060031b1c19161790565b600e5580f35b600e8352601f198216937fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd91845b86811061159e5750836001959610611585575b505050811b01600e5580f35b015160001960f88460031b161c19169055388080611579565b91926020600181928685015181550194019201611566565b600e83526115ff907fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd601f840160051c81019160208510611605575b601f0160051c01906124ac565b38611501565b90915081906115f2565b634e487b7160e01b82526041600452602482fd5b50346101b557806003193601126101b557602060ff600154166040519015158152f35b50346101b557806003193601126101b55761165f6125c3565b60015460ff81161561169f5760ff19166001557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a180f35b638dfc202b60e01b8252600482fd5b50346101b55760403660031901126101b5576116c86122e9565b336001600160a01b038216036116e4576102be906004356127c9565b63334bd91960e11b8252600482fd5b50346101b557806003193601126101b5576003546040516001600160a01b039091168152602090f35b50346101b55760403660031901126101b5576102be60043561173c6122e9565b906117586102b482600052600060205260016040600020015490565b61273e565b50346101b55760203660031901126101b557600160095461178160ff8216156124ff565b60ff1916176009556004358152600860205260408120906005820160018060a01b0381541633148015611827575b6117b89061253c565b600383019060ff82541660038110156118135761180693946117dc60049215612577565b01805490859055825460ff191660021790925560065490546001600160a01b039081169116612651565b60ff196009541660095580f35b634e487b7160e01b84526021600452602484fd5b507f5d8e12c39142ff96d79d04d15d1ba1269e4fe57bb9d26f43523628b34ba108ec82526020828152604080842033855290915282205460ff166117af565b50346101b55760e03660031901126101b55760c4356001600160a01b03811691908290036101b5576118966125c3565b60405191600435602084015260243560408401526044356060840152606435608084015260843560a084015260a43560c084015260e083015260e082526118df61010083612361565b81516001600160401b03811161160f576118fa600d546123ef565b601f81116119b8575b50602092601f821160011461193a578293829161193494926111405750508160011b916000199060031b1c19161790565b600d5580f35b600d8352601f198216937fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb591845b8681106119a05750836001959610611987575b505050811b01600d5580f35b015160001960f88460031b161c1916905538808061197b565b91926020600181928685015181550194019201611968565b600d8352611a00907fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb5601f840160051c8101916020851061160557601f0160051c01906124ac565b38611903565b50346101b55760203660031901126101b557611a206122ce565b611a286125c3565b60018060a01b03166001600160601b0360a01b600654161760065580f35b50346101b55760203660031901126101b5576020611a74600435600052600060205260016040600020015490565b604051908152f35b50346101b55760203660031901126101b557606060c0604051611a9e81612330565b82815282602082015282604082015283838201528360808201528360a0820152015260043581526008602052604081209060405191611adc83612330565b604051611aed816106278185612429565b8352604051611b03816106278160018601612429565b6020840190815260405191611b2683611b1f8160028501612429565b0384612361565b6040850192835260ff6003820154169260608601936003811015611d6257845260048201549060808701918252600660018060a01b036005850154169360a08901948552019360405180958691602082549182815201918a5260208a20908a915b81601f8401106120495792611ca992611ce19592611cf49897955491818110612035575b81811061201e575b818110612007575b818110611ff0575b818110611fda575b818110611fc3575b818110611fac575b818110611f95575b818110611f7e575b818110611f67575b818110611f50575b818110611f39575b818110611f22575b818110611f0b575b818110611ef4575b818110611edd575b818110611ec6575b818110611eaf575b818110611e98575b818110611e81575b818110611e6a575b818110611e53575b818110611e3c575b818110611e25575b818110611e0e575b818110611df7575b818110611de0575b818110611dc9575b818110611db2575b818110611d9b575b818110611d84575b10611d76575b500388612361565b60c08a01968752611cce6040519a60208c525160e060208d01526101008c019061228d565b90518a8203601f190160408c015261228d565b9051888203601f190160608a015261228d565b93516003811015611d625760808701525160a0860152516001600160a01b031660c085015251838203601f190160e085015280518083528493602093840193909201915b818110611d46575050500390f35b825160ff16845285945060209384019390920191600101611d38565b634e487b7160e01b86526021600452602486fd5b60f81c815260200138611ca1565b92602060019160ff8560f01c168152019301611c9b565b92602060019160ff8560e81c168152019301611c93565b92602060019160ff8560e01c168152019301611c8b565b92602060019160ff8560d81c168152019301611c83565b92602060019160ff8560d01c168152019301611c7b565b92602060019160ff8560c81c168152019301611c73565b92602060019160ff8560c01c168152019301611c6b565b92602060019160ff8560b81c168152019301611c63565b92602060019160ff8560b01c168152019301611c5b565b92602060019160ff8560a81c168152019301611c53565b92602060019160ff8560a01c168152019301611c4b565b92602060019160ff8560981c168152019301611c43565b92602060019160ff8560901c168152019301611c3b565b92602060019160ff8560881c168152019301611c33565b92602060019160ff8560801c168152019301611c2b565b92602060019160ff8560781c168152019301611c23565b92602060019160ff8560701c168152019301611c1b565b92602060019160ff8560681c168152019301611c13565b92602060019160ff8560601c168152019301611c0b565b92602060019160ff8560581c168152019301611c03565b92602060019160ff8560501c168152019301611bfb565b92602060019160ff8560481c168152019301611bf3565b92602060019160ff8560401c168152019301611beb565b92602060019160ff8560381c168152019301611be3565b92602060019160ff8560301c168152019301611bdb565b92602060019160ff8560281c168152019301611bd3565b92602060019160ff85831c168152019301611bcb565b92602060019160ff8560181c168152019301611bc3565b92602060019160ff8560101c168152019301611bbb565b92602060019160ff8560081c168152019301611bb3565b92602060019160ff85168152019301611bab565b935090916001610400602092865460ff8116825260ff8160081c168583015260ff8160101c16604083015260ff8160181c16606083015260ff81861c16608083015260ff8160281c1660a083015260ff8160301c1660c083015260ff8160381c1660e083015260ff8160401c1661010083015260ff8160481c1661012083015260ff8160501c1661014083015260ff8160581c1661016083015260ff8160601c1661018083015260ff8160681c166101a083015260ff8160701c166101c083015260ff8160781c166101e083015260ff8160801c1661020083015260ff8160881c1661022083015260ff8160901c1661024083015260ff8160981c1661026083015260ff8160a01c1661028083015260ff8160a81c166102a083015260ff8160b01c166102c083015260ff8160b81c166102e083015260ff8160c01c1661030083015260ff8160c81c1661032083015260ff8160d01c1661034083015260ff8160d81c1661036083015260ff8160e01c1661038083015260ff8160e81c166103a083015260ff8160f01c166103c083015260f81c6103e0820152019401920190889392611b87565b50346101b557806003193601126101b5576006546040516001600160a01b039091168152602090f35b50346101b557806003193601126101b5576020600754604051908152f35b9050346113ff5760203660031901126113ff5760043563ffffffff60e01b811680910361046f5760209250637965db0b60e01b811490811561227c575b5015158152f35b6301ffc9a760e01b14905038612275565b919082519283825260005b8481106122b9575050826000602080949584010152601f8019910116010190565b80602080928401015182828601015201612298565b600435906001600160a01b03821682036122e457565b600080fd5b602435906001600160a01b03821682036122e457565b600a5481101561231a57600a60005260206000200190600090565b634e487b7160e01b600052603260045260246000fd5b60e081019081106001600160401b0382111761234b57604052565b634e487b7160e01b600052604160045260246000fd5b90601f801991011681019081106001600160401b0382111761234b57604052565b81601f820112156122e4578035906001600160401b03821161234b57604051926123b6601f8401601f191660200185612361565b828452602083830101116122e457816000926020809301838601378301015290565b6001600160401b03811161234b5760051b60200190565b90600182811c9216801561241f575b602083101461240957565b634e487b7160e01b600052602260045260246000fd5b91607f16916123fe565b60009291815491612439836123ef565b808352926001811690811561248f575060011461245557505050565b60009081526020812093945091925b838310612475575060209250010190565b600181602092949394548385870101520191019190612464565b915050602093945060ff929192191683830152151560051b010190565b8181106124b7575050565b600081556001016124ac565b9190601f81116124d257505050565b6124fd926000526020600020906020601f840160051c8301931061160557601f0160051c01906124ac565b565b1561250657565b60405162461bcd60e51b815260206004820152600e60248201526d31b0b73737ba103932b2b73a32b960911b6044820152606490fd5b1561254357565b60405162461bcd60e51b815260206004820152600c60248201526b2737ba10383937b837b9b2b960a11b6044820152606490fd5b1561257e57565b60405162461bcd60e51b815260206004820152601960248201527f4170706c69636174696f6e206973206e6f7420616374697665000000000000006044820152606490fd5b3360009081527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5602052604090205460ff16156125fc57565b63e2517d3f60e01b60005233600452600060245260446000fd5b60008181526020818152604080832033845290915290205460ff16156126395750565b63e2517d3f60e01b6000523360045260245260446000fd5b60405163a9059cbb60e01b60208201526001600160a01b0390921660248301526044808301939093529181526124fd91610e00606483612361565b6001600160a01b03811660009081527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5602052604090205460ff16612738576001600160a01b031660008181527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb560205260408120805460ff191660011790553391907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d8180a4600190565b50600090565b6000818152602081815260408083206001600160a01b038616845290915290205460ff166127c2576000818152602081815260408083206001600160a01b0395909516808452949091528120805460ff19166001179055339291907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9080a4600190565b5050600090565b6000818152602081815260408083206001600160a01b038616845290915290205460ff16156127c2576000818152602081815260408083206001600160a01b0395909516808452949091528120805460ff19169055339291907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9080a4600190565b60ff6001541661285757565b63d93c066560e01b60005260046000fd5b906000602091828151910182855af1156128c3576000513d6128ba57506001600160a01b0381163b155b6128995750565b635274afe760e01b60009081526001600160a01b0391909116600452602490fd5b60011415612892565b6040513d6000823e3d90fdfef0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00a264697066735822122092d21f722413106e34835bf19607b553546784a20a8755d5d9dd69dcab773aa164736f6c634300081c0033

Block Transaction Gas Used Reward
view all blocks produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.