diff --git a/.openzeppelin/base-sepolia.json b/.openzeppelin/base-sepolia.json index c4236c2..78aceaf 100644 --- a/.openzeppelin/base-sepolia.json +++ b/.openzeppelin/base-sepolia.json @@ -348,6 +348,31 @@ "address": "0xaC92149dd9569732Aec1deB93Bc0b8194AAe7aD1", "txHash": "0x4af4ef10bd4a010109fe15f5fe914ee6698ed5fa6b1398134d47ee464f407304", "kind": "transparent" + }, + { + "address": "0xE3AAa69b5bD8B8d74d7bd427142DE9ABaa41Ada3", + "txHash": "0x8ba2a6ec79b1b19837905fa737611b1d7841c0431aaf4edb11d5431768388993", + "kind": "transparent" + }, + { + "address": "0x9389B0Fd34d0Dc65F2fc0c19Eeaf1B74938F58ec", + "txHash": "0x83773e41ceff6ec4de130dcd962c3ab4f06b3d1e6bc379f1f2e9271c4273ced1", + "kind": "transparent" + }, + { + "address": "0xD50F5489b19e9d882c0457D7E4f14A622d5BEB30", + "txHash": "0xe536cf789a6f3c6929ff65601084e989eb0cf821001534085c8dde6809595bac", + "kind": "transparent" + }, + { + "address": "0x21a8ad39Cf42F84bc4d4848b8FE653f4EbE59720", + "txHash": "0x27a9dd5ba825d329ed1155b4857a4288441ed21940aa81b69a7435b02eae404b", + "kind": "transparent" + }, + { + "address": "0xF4C66B6098F646B869e342E83B410473d27E40df", + "txHash": "0xd9484a43b60c21fa49f1683fe48de9a920cf6224520e1119996fd677c091cd05", + "kind": "transparent" } ], "impls": { @@ -28068,6 +28093,1356 @@ ] } } + }, + "0b6fcbbe4012176cf4d860fea9586db94ddaf8b18cb27770abf09340d85f0347": { + "address": "0xE1FB9859D6D62ceccc465939A027EC37a4Ae985a", + "txHash": "0xbc3c9945bb86e6b916cd31a03ea8a985dd0d3946d14295749e7d7a42d29bfe81", + "layout": { + "solcVersion": "0.8.26", + "storage": [ + { + "label": "_roles", + "offset": 0, + "slot": "0", + "type": "t_mapping(t_bytes32,t_struct(RoleData)900_storage)", + "contract": "AccessControl", + "src": "@openzeppelin/contracts/access/AccessControl.sol:55" + }, + { + "label": "_nextId", + "offset": 0, + "slot": "1", + "type": "t_uint256", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:27" + }, + { + "label": "tokenImplementation", + "offset": 0, + "slot": "2", + "type": "t_address", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:28" + }, + { + "label": "daoImplementation", + "offset": 0, + "slot": "3", + "type": "t_address", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:29" + }, + { + "label": "nft", + "offset": 0, + "slot": "4", + "type": "t_address", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:30" + }, + { + "label": "tbaRegistry", + "offset": 0, + "slot": "5", + "type": "t_address", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:31" + }, + { + "label": "applicationThreshold", + "offset": 0, + "slot": "6", + "type": "t_uint256", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:32" + }, + { + "label": "allTokens", + "offset": 0, + "slot": "7", + "type": "t_array(t_address)dyn_storage", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:34" + }, + { + "label": "allDAOs", + "offset": 0, + "slot": "8", + "type": "t_array(t_address)dyn_storage", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:35" + }, + { + "label": "assetToken", + "offset": 0, + "slot": "9", + "type": "t_address", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:37" + }, + { + "label": "maturityDuration", + "offset": 0, + "slot": "10", + "type": "t_uint256", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:38" + }, + { + "label": "_applications", + "offset": 0, + "slot": "11", + "type": "t_mapping(t_uint256,t_struct(Application)5186_storage)", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:74" + }, + { + "label": "gov", + "offset": 0, + "slot": "12", + "type": "t_address", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:76" + }, + { + "label": "_vault", + "offset": 0, + "slot": "13", + "type": "t_address", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:87" + }, + { + "label": "locked", + "offset": 20, + "slot": "13", + "type": "t_bool", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:89" + }, + { + "label": "allTradingTokens", + "offset": 0, + "slot": "14", + "type": "t_array(t_address)dyn_storage", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:101" + }, + { + "label": "_uniswapRouter", + "offset": 0, + "slot": "15", + "type": "t_address", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:102" + }, + { + "label": "veTokenImplementation", + "offset": 0, + "slot": "16", + "type": "t_address", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:103" + }, + { + "label": "_minter", + "offset": 0, + "slot": "17", + "type": "t_address", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:104" + }, + { + "label": "_tokenAdmin", + "offset": 0, + "slot": "18", + "type": "t_address", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:105" + }, + { + "label": "defaultDelegatee", + "offset": 0, + "slot": "19", + "type": "t_address", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:106" + }, + { + "label": "_tokenSupplyParams", + "offset": 0, + "slot": "20", + "type": "t_bytes_storage", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:109" + }, + { + "label": "_tokenTaxParams", + "offset": 0, + "slot": "21", + "type": "t_bytes_storage", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:110" + }, + { + "label": "_tokenMultiplier", + "offset": 0, + "slot": "22", + "type": "t_uint16", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:111" + }, + { + "label": "_existingAgents", + "offset": 0, + "slot": "23", + "type": "t_mapping(t_address,t_bool)", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:117" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)93_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(PausableStorage)165_storage": { + "label": "struct PausableUpgradeable.PausableStorage", + "members": [ + { + "label": "_paused", + "type": "t_bool", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_address)dyn_storage": { + "label": "address[]", + "numberOfBytes": "32" + }, + "t_array(t_uint8)dyn_storage": { + "label": "uint8[]", + "numberOfBytes": "32" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_bytes_storage": { + "label": "bytes", + "numberOfBytes": "32" + }, + "t_enum(ApplicationStatus)5157": { + "label": "enum AgentFactoryV5.ApplicationStatus", + "members": [ + "Active", + "Executed", + "Withdrawn" + ], + "numberOfBytes": "1" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_struct(RoleData)900_storage)": { + "label": "mapping(bytes32 => struct AccessControl.RoleData)", + "numberOfBytes": "32" + }, + "t_mapping(t_uint256,t_struct(Application)5186_storage)": { + "label": "mapping(uint256 => struct AgentFactoryV5.Application)", + "numberOfBytes": "32" + }, + "t_string_storage": { + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(Application)5186_storage": { + "label": "struct AgentFactoryV5.Application", + "members": [ + { + "label": "name", + "type": "t_string_storage", + "offset": 0, + "slot": "0" + }, + { + "label": "symbol", + "type": "t_string_storage", + "offset": 0, + "slot": "1" + }, + { + "label": "tokenURI", + "type": "t_string_storage", + "offset": 0, + "slot": "2" + }, + { + "label": "status", + "type": "t_enum(ApplicationStatus)5157", + "offset": 0, + "slot": "3" + }, + { + "label": "withdrawableAmount", + "type": "t_uint256", + "offset": 0, + "slot": "4" + }, + { + "label": "proposer", + "type": "t_address", + "offset": 0, + "slot": "5" + }, + { + "label": "cores", + "type": "t_array(t_uint8)dyn_storage", + "offset": 0, + "slot": "6" + }, + { + "label": "proposalEndBlock", + "type": "t_uint256", + "offset": 0, + "slot": "7" + }, + { + "label": "virtualId", + "type": "t_uint256", + "offset": 0, + "slot": "8" + }, + { + "label": "tbaSalt", + "type": "t_bytes32", + "offset": 0, + "slot": "9" + }, + { + "label": "tbaImplementation", + "type": "t_address", + "offset": 0, + "slot": "10" + }, + { + "label": "daoVotingPeriod", + "type": "t_uint32", + "offset": 20, + "slot": "10" + }, + { + "label": "daoThreshold", + "type": "t_uint256", + "offset": 0, + "slot": "11" + } + ], + "numberOfBytes": "384" + }, + "t_struct(RoleData)900_storage": { + "label": "struct AccessControl.RoleData", + "members": [ + { + "label": "hasRole", + "type": "t_mapping(t_address,t_bool)", + "offset": 0, + "slot": "0" + }, + { + "label": "adminRole", + "type": "t_bytes32", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint32": { + "label": "uint32", + "numberOfBytes": "4" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.Pausable": [ + { + "contract": "PausableUpgradeable", + "label": "_paused", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol:21", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + }, + "e98c4a4d4c896f78c9fa7ebed77c857c64d2d983ecfc8d009859055470ba6067": { + "address": "0xd24C61D5673e98b57756428Af9f9d24e86f56b5d", + "txHash": "0x4f51d400ca717f2f9c019861aeab381466037b41f7a8b4714f8d7b0ad73f98f2", + "layout": { + "solcVersion": "0.8.26", + "storage": [ + { + "label": "params", + "offset": 0, + "slot": "0", + "type": "t_struct(Params)2045_storage", + "contract": "FGenesis", + "src": "contracts/genesis/FGenesis.sol:33" + }, + { + "label": "genesisContracts", + "offset": 0, + "slot": "12", + "type": "t_mapping(t_uint256,t_address)", + "contract": "FGenesis", + "src": "contracts/genesis/FGenesis.sol:34" + }, + { + "label": "genesisID", + "offset": 0, + "slot": "13", + "type": "t_uint256", + "contract": "FGenesis", + "src": "contracts/genesis/FGenesis.sol:35" + } + ], + "types": { + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_struct(RoleData)25_storage)": { + "label": "mapping(bytes32 => struct AccessControlUpgradeable.RoleData)", + "numberOfBytes": "32" + }, + "t_struct(AccessControlStorage)34_storage": { + "label": "struct AccessControlUpgradeable.AccessControlStorage", + "members": [ + { + "label": "_roles", + "type": "t_mapping(t_bytes32,t_struct(RoleData)25_storage)", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(InitializableStorage)93_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(RoleData)25_storage": { + "label": "struct AccessControlUpgradeable.RoleData", + "members": [ + { + "label": "hasRole", + "type": "t_mapping(t_address,t_bool)", + "offset": 0, + "slot": "0" + }, + { + "label": "adminRole", + "type": "t_bytes32", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_mapping(t_uint256,t_address)": { + "label": "mapping(uint256 => address)", + "numberOfBytes": "32" + }, + "t_struct(Params)2045_storage": { + "label": "struct FGenesis.Params", + "members": [ + { + "label": "virtualToken", + "type": "t_address", + "offset": 0, + "slot": "0" + }, + { + "label": "reserve", + "type": "t_uint256", + "offset": 0, + "slot": "1" + }, + { + "label": "maxContribution", + "type": "t_uint256", + "offset": 0, + "slot": "2" + }, + { + "label": "feeAddr", + "type": "t_address", + "offset": 0, + "slot": "3" + }, + { + "label": "feeAmt", + "type": "t_uint256", + "offset": 0, + "slot": "4" + }, + { + "label": "duration", + "type": "t_uint256", + "offset": 0, + "slot": "5" + }, + { + "label": "tbaSalt", + "type": "t_bytes32", + "offset": 0, + "slot": "6" + }, + { + "label": "tbaImpl", + "type": "t_address", + "offset": 0, + "slot": "7" + }, + { + "label": "votePeriod", + "type": "t_uint32", + "offset": 20, + "slot": "7" + }, + { + "label": "threshold", + "type": "t_uint256", + "offset": 0, + "slot": "8" + }, + { + "label": "agentFactory", + "type": "t_address", + "offset": 0, + "slot": "9" + }, + { + "label": "agentTokenTotalSupply", + "type": "t_uint256", + "offset": 0, + "slot": "10" + }, + { + "label": "agentTokenLpSupply", + "type": "t_uint256", + "offset": 0, + "slot": "11" + } + ], + "numberOfBytes": "384" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint32": { + "label": "uint32", + "numberOfBytes": "4" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.AccessControl": [ + { + "contract": "AccessControlUpgradeable", + "label": "_roles", + "type": "t_mapping(t_bytes32,t_struct(RoleData)25_storage)", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:61", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + }, + "e5915d614faee7ab227a32d032a3113eedc6ebe90327059cd3f67d741d04b1b2": { + "address": "0x089Fd52B09b3aC5FB1d6029B7cf38be49aB58bea", + "txHash": "0xb6de45fa850566b8360d81dcf4c85d937c428bd98310989abc23913e1b9da1a1", + "layout": { + "solcVersion": "0.8.26", + "storage": [ + { + "label": "params", + "offset": 0, + "slot": "0", + "type": "t_struct(Params)2045_storage", + "contract": "FGenesis", + "src": "contracts/genesis/FGenesis.sol:33" + }, + { + "label": "genesisContracts", + "offset": 0, + "slot": "12", + "type": "t_mapping(t_uint256,t_address)", + "contract": "FGenesis", + "src": "contracts/genesis/FGenesis.sol:34" + }, + { + "label": "genesisID", + "offset": 0, + "slot": "13", + "type": "t_uint256", + "contract": "FGenesis", + "src": "contracts/genesis/FGenesis.sol:35" + } + ], + "types": { + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_struct(RoleData)25_storage)": { + "label": "mapping(bytes32 => struct AccessControlUpgradeable.RoleData)", + "numberOfBytes": "32" + }, + "t_struct(AccessControlStorage)34_storage": { + "label": "struct AccessControlUpgradeable.AccessControlStorage", + "members": [ + { + "label": "_roles", + "type": "t_mapping(t_bytes32,t_struct(RoleData)25_storage)", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(InitializableStorage)93_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(RoleData)25_storage": { + "label": "struct AccessControlUpgradeable.RoleData", + "members": [ + { + "label": "hasRole", + "type": "t_mapping(t_address,t_bool)", + "offset": 0, + "slot": "0" + }, + { + "label": "adminRole", + "type": "t_bytes32", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_mapping(t_uint256,t_address)": { + "label": "mapping(uint256 => address)", + "numberOfBytes": "32" + }, + "t_struct(Params)2045_storage": { + "label": "struct FGenesis.Params", + "members": [ + { + "label": "virtualToken", + "type": "t_address", + "offset": 0, + "slot": "0" + }, + { + "label": "reserve", + "type": "t_uint256", + "offset": 0, + "slot": "1" + }, + { + "label": "maxContribution", + "type": "t_uint256", + "offset": 0, + "slot": "2" + }, + { + "label": "feeAddr", + "type": "t_address", + "offset": 0, + "slot": "3" + }, + { + "label": "feeAmt", + "type": "t_uint256", + "offset": 0, + "slot": "4" + }, + { + "label": "duration", + "type": "t_uint256", + "offset": 0, + "slot": "5" + }, + { + "label": "tbaSalt", + "type": "t_bytes32", + "offset": 0, + "slot": "6" + }, + { + "label": "tbaImpl", + "type": "t_address", + "offset": 0, + "slot": "7" + }, + { + "label": "votePeriod", + "type": "t_uint32", + "offset": 20, + "slot": "7" + }, + { + "label": "threshold", + "type": "t_uint256", + "offset": 0, + "slot": "8" + }, + { + "label": "agentFactory", + "type": "t_address", + "offset": 0, + "slot": "9" + }, + { + "label": "agentTokenTotalSupply", + "type": "t_uint256", + "offset": 0, + "slot": "10" + }, + { + "label": "agentTokenLpSupply", + "type": "t_uint256", + "offset": 0, + "slot": "11" + } + ], + "numberOfBytes": "384" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint32": { + "label": "uint32", + "numberOfBytes": "4" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.AccessControl": [ + { + "contract": "AccessControlUpgradeable", + "label": "_roles", + "type": "t_mapping(t_bytes32,t_struct(RoleData)25_storage)", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:61", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } + }, + "49422371d4985415506dc22398f112bcbe7964f405aec22a91074326aefd9939": { + "address": "0x05152deb1BA3862A727D3cd674DaeE9f256442a6", + "txHash": "0xb58fe293c6d5b4d3fb48cab3759004c4b1a9851e21e7c2e2f730360c49845d6e", + "layout": { + "solcVersion": "0.8.26", + "storage": [ + { + "label": "_roles", + "offset": 0, + "slot": "0", + "type": "t_mapping(t_bytes32,t_struct(RoleData)497_storage)", + "contract": "AccessControl", + "src": "@openzeppelin/contracts/access/AccessControl.sol:55" + }, + { + "label": "_nextId", + "offset": 0, + "slot": "1", + "type": "t_uint256", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:27" + }, + { + "label": "tokenImplementation", + "offset": 0, + "slot": "2", + "type": "t_address", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:28" + }, + { + "label": "daoImplementation", + "offset": 0, + "slot": "3", + "type": "t_address", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:29" + }, + { + "label": "nft", + "offset": 0, + "slot": "4", + "type": "t_address", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:30" + }, + { + "label": "tbaRegistry", + "offset": 0, + "slot": "5", + "type": "t_address", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:31" + }, + { + "label": "applicationThreshold", + "offset": 0, + "slot": "6", + "type": "t_uint256", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:32" + }, + { + "label": "allTokens", + "offset": 0, + "slot": "7", + "type": "t_array(t_address)dyn_storage", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:34" + }, + { + "label": "allDAOs", + "offset": 0, + "slot": "8", + "type": "t_array(t_address)dyn_storage", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:35" + }, + { + "label": "assetToken", + "offset": 0, + "slot": "9", + "type": "t_address", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:37" + }, + { + "label": "maturityDuration", + "offset": 0, + "slot": "10", + "type": "t_uint256", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:38" + }, + { + "label": "_applications", + "offset": 0, + "slot": "11", + "type": "t_mapping(t_uint256,t_struct(Application)2388_storage)", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:74" + }, + { + "label": "gov", + "offset": 0, + "slot": "12", + "type": "t_address", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:76" + }, + { + "label": "_vault", + "offset": 0, + "slot": "13", + "type": "t_address", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:87" + }, + { + "label": "locked", + "offset": 20, + "slot": "13", + "type": "t_bool", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:89" + }, + { + "label": "allTradingTokens", + "offset": 0, + "slot": "14", + "type": "t_array(t_address)dyn_storage", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:101" + }, + { + "label": "_uniswapRouter", + "offset": 0, + "slot": "15", + "type": "t_address", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:102" + }, + { + "label": "veTokenImplementation", + "offset": 0, + "slot": "16", + "type": "t_address", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:103" + }, + { + "label": "_minter", + "offset": 0, + "slot": "17", + "type": "t_address", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:104" + }, + { + "label": "_tokenAdmin", + "offset": 0, + "slot": "18", + "type": "t_address", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:105" + }, + { + "label": "defaultDelegatee", + "offset": 0, + "slot": "19", + "type": "t_address", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:106" + }, + { + "label": "_tokenSupplyParams", + "offset": 0, + "slot": "20", + "type": "t_bytes_storage", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:109" + }, + { + "label": "_tokenTaxParams", + "offset": 0, + "slot": "21", + "type": "t_bytes_storage", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:110" + }, + { + "label": "_tokenMultiplier", + "offset": 0, + "slot": "22", + "type": "t_uint16", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:111" + }, + { + "label": "_existingAgents", + "offset": 0, + "slot": "23", + "type": "t_mapping(t_address,t_bool)", + "contract": "AgentFactoryV5", + "src": "contracts/virtualPersona/AgentFactoryV5.sol:117" + } + ], + "types": { + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_struct(InitializableStorage)10_storage": { + "label": "struct Initializable.InitializableStorage", + "members": [ + { + "label": "_initialized", + "type": "t_uint64", + "offset": 0, + "slot": "0" + }, + { + "label": "_initializing", + "type": "t_bool", + "offset": 8, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(PausableStorage)82_storage": { + "label": "struct PausableUpgradeable.PausableStorage", + "members": [ + { + "label": "_paused", + "type": "t_bool", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_uint64": { + "label": "uint64", + "numberOfBytes": "8" + }, + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_address)dyn_storage": { + "label": "address[]", + "numberOfBytes": "32" + }, + "t_array(t_uint8)dyn_storage": { + "label": "uint8[]", + "numberOfBytes": "32" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_bytes_storage": { + "label": "bytes", + "numberOfBytes": "32" + }, + "t_enum(ApplicationStatus)2359": { + "label": "enum AgentFactoryV5.ApplicationStatus", + "members": [ + "Active", + "Executed", + "Withdrawn" + ], + "numberOfBytes": "1" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_struct(RoleData)497_storage)": { + "label": "mapping(bytes32 => struct AccessControl.RoleData)", + "numberOfBytes": "32" + }, + "t_mapping(t_uint256,t_struct(Application)2388_storage)": { + "label": "mapping(uint256 => struct AgentFactoryV5.Application)", + "numberOfBytes": "32" + }, + "t_string_storage": { + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(Application)2388_storage": { + "label": "struct AgentFactoryV5.Application", + "members": [ + { + "label": "name", + "type": "t_string_storage", + "offset": 0, + "slot": "0" + }, + { + "label": "symbol", + "type": "t_string_storage", + "offset": 0, + "slot": "1" + }, + { + "label": "tokenURI", + "type": "t_string_storage", + "offset": 0, + "slot": "2" + }, + { + "label": "status", + "type": "t_enum(ApplicationStatus)2359", + "offset": 0, + "slot": "3" + }, + { + "label": "withdrawableAmount", + "type": "t_uint256", + "offset": 0, + "slot": "4" + }, + { + "label": "proposer", + "type": "t_address", + "offset": 0, + "slot": "5" + }, + { + "label": "cores", + "type": "t_array(t_uint8)dyn_storage", + "offset": 0, + "slot": "6" + }, + { + "label": "proposalEndBlock", + "type": "t_uint256", + "offset": 0, + "slot": "7" + }, + { + "label": "virtualId", + "type": "t_uint256", + "offset": 0, + "slot": "8" + }, + { + "label": "tbaSalt", + "type": "t_bytes32", + "offset": 0, + "slot": "9" + }, + { + "label": "tbaImplementation", + "type": "t_address", + "offset": 0, + "slot": "10" + }, + { + "label": "daoVotingPeriod", + "type": "t_uint32", + "offset": 20, + "slot": "10" + }, + { + "label": "daoThreshold", + "type": "t_uint256", + "offset": 0, + "slot": "11" + } + ], + "numberOfBytes": "384" + }, + "t_struct(RoleData)497_storage": { + "label": "struct AccessControl.RoleData", + "members": [ + { + "label": "hasRole", + "type": "t_mapping(t_address,t_bool)", + "offset": 0, + "slot": "0" + }, + { + "label": "adminRole", + "type": "t_bytes32", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_uint16": { + "label": "uint16", + "numberOfBytes": "2" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint32": { + "label": "uint32", + "numberOfBytes": "4" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + }, + "namespaces": { + "erc7201:openzeppelin.storage.Pausable": [ + { + "contract": "PausableUpgradeable", + "label": "_paused", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol:21", + "offset": 0, + "slot": "0" + } + ], + "erc7201:openzeppelin.storage.Initializable": [ + { + "contract": "Initializable", + "label": "_initialized", + "type": "t_uint64", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:69", + "offset": 0, + "slot": "0" + }, + { + "contract": "Initializable", + "label": "_initializing", + "type": "t_bool", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:73", + "offset": 8, + "slot": "0" + } + ] + } + } } } } diff --git a/contracts/genesis/FGenesis.sol b/contracts/genesis/FGenesis.sol index 1119d89..5509a0c 100644 --- a/contracts/genesis/FGenesis.sol +++ b/contracts/genesis/FGenesis.sol @@ -56,23 +56,15 @@ contract FGenesis is Initializable, AccessControlUpgradeable { function _setParams(Params memory p) internal { require( - p.virtualToken != address(0) && - p.feeAddr != address(0) && - p.tbaImpl != address(0) && - p.agentFactory != address(0), - "Invalid addr" + p.virtualToken != address(0) && p.feeAddr != address(0) && + p.tbaImpl != address(0) && p.agentFactory != address(0), + "Zero addr" ); require( - p.reserve > 0 && p.maxContribution > 0 && p.feeAmt > 0, - "Invalid amt" - ); - - require( - p.duration > 0 && - p.agentTokenTotalSupply > 0 && - p.agentTokenLpSupply > 0 && - p.agentTokenTotalSupply >= p.agentTokenLpSupply, + p.reserve > 0 && p.maxContribution > 0 && p.feeAmt > 0 && + p.duration > 0 && p.agentTokenTotalSupply > 0 && + p.agentTokenLpSupply > 0 && p.agentTokenTotalSupply >= p.agentTokenLpSupply, "Invalid amt" ); @@ -80,15 +72,13 @@ contract FGenesis is Initializable, AccessControlUpgradeable { } function createGenesis( - GenesisCreationParams memory gParams + GenesisCreationParams memory gParams, + bool noLpStake ) external returns (address) { - require( - IERC20(params.virtualToken).transferFrom( - msg.sender, - params.feeAddr, - params.feeAmt - ), - "transfer createGenesis fee failed" + IERC20(params.virtualToken).transferFrom( + msg.sender, + params.feeAddr, + params.feeAmt ); gParams.endTime = gParams.startTime + params.duration; @@ -106,7 +96,8 @@ contract FGenesis is Initializable, AccessControlUpgradeable { params.reserve, params.maxContribution, params.agentTokenTotalSupply, - params.agentTokenLpSupply + params.agentTokenLpSupply, + noLpStake ); IAccessControl(params.agentFactory).grantRole( @@ -125,19 +116,6 @@ contract FGenesis is Initializable, AccessControlUpgradeable { return Genesis(addr); } - function onGenesisSuccess( - uint256 id, - SuccessParams calldata p - ) external onlyRole(OPERATION_ROLE) returns (address) { - return - _getGenesis(id).onGenesisSuccess( - p.refundAddresses, - p.refundAmounts, - p.distributeAddresses, - p.distributeAmounts, - p.creator - ); - } function onGenesisSuccessSalt( uint256 id, diff --git a/contracts/genesis/Genesis.sol b/contracts/genesis/Genesis.sol index 4346c85..9173f1d 100644 --- a/contracts/genesis/Genesis.sol +++ b/contracts/genesis/Genesis.sol @@ -5,7 +5,7 @@ import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./FGenesis.sol"; -import "../virtualPersona/IAgentFactoryV3.sol"; +import "../virtualPersona/IAgentFactoryV5.sol"; // import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "./GenesisTypes.sol"; @@ -45,6 +45,8 @@ contract Genesis is ReentrancyGuard, AccessControlUpgradeable { address public agentTokenAddress; bool public isFailed; bool public isCancelled; + bool public noLpStake; + uint256 public totalClaimableAgentTokensLeft; event AssetsWithdrawn( uint256 indexed genesisID, @@ -99,6 +101,8 @@ contract Genesis is ReentrancyGuard, AccessControlUpgradeable { "End time must be after start time"; string private constant ERR_TOKEN_LAUNCHED = "Agent token already launched"; string private constant ERR_TOKEN_NOT_LAUNCHED = "Agent token not launched"; + string private constant ERR_ZERO_ADD = "Address cannot be empty"; + string private constant ERR_INVALID_PARAM = "Invalid value for parameter"; // Common validation modifiers modifier whenNotStarted() { @@ -169,46 +173,24 @@ contract Genesis is ReentrancyGuard, AccessControlUpgradeable { ) external initializer { __AccessControl_init(); - require(params.genesisID > 0, "Invalid genesis ID"); - require(params.factory != address(0), "Invalid factory address"); + require(params.genesisID > 0, "Invalid ID"); + require(params.factory != address(0) && params.tbaImplementation != address(0) + && params.agentFactoryAddress != address(0) && params.virtualTokenAddress != address(0), ERR_ZERO_ADD); _validateTime(params.startTime, params.endTime); - require(bytes(params.genesisName).length > 0, "Invalid genesis name"); + require(bytes(params.genesisName).length > 0, "Invalid name"); require( bytes(params.genesisTicker).length > 0, - "Invalid genesis ticker" + "Invalid ticker" ); - require(params.genesisCores.length > 0, "Invalid genesis cores"); + require(params.genesisCores.length > 0, "Invalid cores"); require( - params.tbaImplementation != address(0), - "Invalid TBA implementation address" - ); - require( - params.agentFactoryAddress != address(0), - "Invalid agent factory address" - ); - require( - params.virtualTokenAddress != address(0), - "Invalid virtual token address" - ); - require( - params.reserveAmount > 0, - "Reserve amount must be greater than 0" - ); - require( - params.maxContributionVirtualAmount > 0, - "Max contribution must be greater than 0" - ); - require( - params.agentTokenTotalSupply > 0, - "Agent token total supply must be greater than 0" - ); - require( - params.agentTokenLpSupply > 0, - "Agent token lp supply must be greater than 0" + params.reserveAmount > 0 && params.maxContributionVirtualAmount > 0 + && params.agentTokenTotalSupply > 0 && params.agentTokenLpSupply > 0, + ERR_INVALID_PARAM ); require( params.agentTokenTotalSupply >= params.agentTokenLpSupply, - "Agent token total supply must be greater than agent token lp supply" + "Agent token total supply must be > agent token lp supply" ); genesisId = params.genesisID; @@ -228,6 +210,7 @@ contract Genesis is ReentrancyGuard, AccessControlUpgradeable { maxContributionVirtualAmount = params.maxContributionVirtualAmount; agentTokenTotalSupply = params.agentTokenTotalSupply; agentTokenLpSupply = params.agentTokenLpSupply; + noLpStake = params.noLpStake; _grantRole(DEFAULT_ADMIN_ROLE, params.factory); _grantRole(FACTORY_ROLE, params.factory); @@ -237,8 +220,8 @@ contract Genesis is ReentrancyGuard, AccessControlUpgradeable { uint256 pointAmt, uint256 virtualsAmt ) external nonReentrant whenActive { - require(pointAmt > 0, "Point amount must be greater than 0"); - require(virtualsAmt > 0, "Virtuals must be greater than 0"); + require(pointAmt > 0, "Point amount must be > 0"); + require(virtualsAmt > 0, "Virtuals must be > 0"); // Check single submission upper limit require( @@ -263,31 +246,6 @@ contract Genesis is ReentrancyGuard, AccessControlUpgradeable { emit Participated(genesisId, msg.sender, pointAmt, virtualsAmt); } - function onGenesisSuccess( - address[] calldata refundVirtualsTokenUserAddresses, - uint256[] calldata refundVirtualsTokenUserAmounts, - address[] calldata distributeAgentTokenUserAddresses, - uint256[] calldata distributeAgentTokenUserAmounts, - address creator - ) - external - onlyRole(FACTORY_ROLE) - nonReentrant - whenNotCancelled - whenEnded - returns (address) - { - return - _onGenesisSuccessSalt( - refundVirtualsTokenUserAddresses, - refundVirtualsTokenUserAmounts, - distributeAgentTokenUserAddresses, - distributeAgentTokenUserAmounts, - creator, - keccak256(abi.encodePacked(msg.sender, block.timestamp)) - ); - } - function onGenesisSuccessSalt( address[] calldata refundVirtualsTokenUserAddresses, uint256[] calldata refundVirtualsTokenUserAmounts, @@ -350,7 +308,7 @@ contract Genesis is ReentrancyGuard, AccessControlUpgradeable { ); // Call initFromBondingCurve and executeBondingCurveApplication - uint256 id = IAgentFactoryV3(agentFactoryAddress) + uint256 id = IAgentFactoryV5(agentFactoryAddress) .initFromBondingCurve( string.concat(genesisName, " by Virtuals"), genesisTicker, @@ -363,16 +321,17 @@ contract Genesis is ReentrancyGuard, AccessControlUpgradeable { creator ); - address agentToken = IAgentFactoryV3(agentFactoryAddress) + address agentToken = IAgentFactoryV5(agentFactoryAddress) .executeBondingCurveApplicationSalt( id, agentTokenTotalSupply, agentTokenLpSupply, address(this), // vault - salt + salt, + noLpStake ); - require(agentToken != address(0), "Agent token creation failed"); + require(agentToken != address(0), ERR_ZERO_ADD); // Store the created agent token address agentTokenAddress = agentToken; @@ -410,9 +369,13 @@ contract Genesis is ReentrancyGuard, AccessControlUpgradeable { // save the amount of agent tokens to claim for (uint256 i = 0; i < distributeAgentTokenUserAddresses.length; i++) { + totalClaimableAgentTokensLeft -= claimableAgentTokens[ + distributeAgentTokenUserAddresses[i] + ]; // because here is replace update, so we need to minus the old amount claimableAgentTokens[ distributeAgentTokenUserAddresses[i] ] = distributeAgentTokenUserAmounts[i]; + totalClaimableAgentTokensLeft += distributeAgentTokenUserAmounts[i]; } emit GenesisSucceeded(genesisId); @@ -425,6 +388,7 @@ contract Genesis is ReentrancyGuard, AccessControlUpgradeable { require(amount > 0, "No tokens to claim"); // set the amount of claimable agent tokens to 0, to prevent duplicate claims + totalClaimableAgentTokensLeft -= amount; claimableAgentTokens[userAddress] = 0; // transfer the agent token @@ -597,7 +561,7 @@ contract Genesis is ReentrancyGuard, AccessControlUpgradeable { whenEnded whenFinalized { - require(token != address(0), "Invalid token address"); + require(token != address(0), ERR_ZERO_ADD); require( amount <= IERC20(token).balanceOf(address(this)), "Insufficient balance to withdraw" diff --git a/contracts/genesis/GenesisLib.sol b/contracts/genesis/GenesisLib.sol index db5009f..f305148 100644 --- a/contracts/genesis/GenesisLib.sol +++ b/contracts/genesis/GenesisLib.sol @@ -19,7 +19,8 @@ library GenesisLib { uint256 reserve, uint256 maxContribution, uint256 agentTokenTotalSupply, - uint256 agentTokenLpSupply + uint256 agentTokenLpSupply, + bool noLpStake ) internal returns (address) { require( bytes(params.genesisName).length > 0 && @@ -47,7 +48,8 @@ library GenesisLib { reserveAmount: reserve, maxContributionVirtualAmount: maxContribution, agentTokenTotalSupply: agentTokenTotalSupply, - agentTokenLpSupply: agentTokenLpSupply + agentTokenLpSupply: agentTokenLpSupply, + noLpStake: noLpStake }); newGenesis.initialize(initParams); diff --git a/contracts/genesis/GenesisTypes.sol b/contracts/genesis/GenesisTypes.sol index be7a9c2..3026246 100644 --- a/contracts/genesis/GenesisTypes.sol +++ b/contracts/genesis/GenesisTypes.sol @@ -35,4 +35,5 @@ struct GenesisInitParams { uint256 maxContributionVirtualAmount; uint256 agentTokenTotalSupply; uint256 agentTokenLpSupply; + bool noLpStake; } diff --git a/contracts/genesis/MockAgentFactoryV5.sol b/contracts/genesis/MockAgentFactoryV5.sol new file mode 100644 index 0000000..d5ec133 --- /dev/null +++ b/contracts/genesis/MockAgentFactoryV5.sol @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.26; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "../virtualPersona/IAgentFactoryV5.sol"; +import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; + +contract MockAgentFactoryV5 is + IAgentFactoryV5, + Initializable, + AccessControlUpgradeable, + PausableUpgradeable +{ + // Mock variables + address public mockAgentToken; + uint256 public mockId; + bytes32 public constant BONDING_ROLE = keccak256("BONDING_ROLE"); + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize( + address, // tokenImplementation + address, // veTokenImplementation + address, // daoImplementation + address, // tbaRegistry + address, // assetToken + address, // nft + uint256, // applicationThreshold + address, // vault + uint256 // nextId + ) public initializer { + __AccessControl_init(); + __Pausable_init(); + _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); + _grantRole(BONDING_ROLE, msg.sender); + } + + // Mock setter functions + function setMockAgentToken(address token) external { + mockAgentToken = token; + } + + function setMockId(uint256 id) external { + mockId = id; + } + + // Interface implementations + function proposeAgent( + string memory, + string memory, + string memory, + uint8[] memory, + bytes32, + address, + uint32, + uint256 + ) public view returns (uint256) { + return mockId; + } + + function withdraw(uint256) public pure { + // Mock implementation - do nothing + } + + function totalAgents() public pure returns (uint256) { + return 1; // Mock implementation returns 1 + } + + function initFromBondingCurve( + string memory, + string memory, + uint8[] memory, + bytes32, + address, + uint32, + uint256, + uint256, + address + ) public view whenNotPaused onlyRole(BONDING_ROLE) returns (uint256) { + return mockId; + } + + function executeBondingCurveApplicationSalt( + uint256, + uint256, + uint256, + address, + bytes32, + bool + ) public view onlyRole(BONDING_ROLE) returns (address) { + return address(mockAgentToken); + } +} diff --git a/contracts/virtualPersona/AgentFactoryV5.sol b/contracts/virtualPersona/AgentFactoryV5.sol new file mode 100644 index 0000000..4c16681 --- /dev/null +++ b/contracts/virtualPersona/AgentFactoryV5.sol @@ -0,0 +1,599 @@ +// 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/access/AccessControl.sol"; +import "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; + +import "./IAgentFactoryV5.sol"; +import "./IAgentToken.sol"; +import "./IAgentVeToken.sol"; +import "./IAgentDAO.sol"; +import "./IAgentNft.sol"; +import "../libs/IERC6551Registry.sol"; + +contract AgentFactoryV5 is + IAgentFactoryV5, + Initializable, + AccessControl, + PausableUpgradeable +{ + 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; + + address public gov; // Deprecated in v2, execution of application does not require DAO decision anymore + + modifier onlyGov() { + require(msg.sender == gov, "Only DAO can execute proposal"); + _; + } + + 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 _minter; // Unused + address private _tokenAdmin; + address public defaultDelegatee; + + // Default agent token params + bytes private _tokenSupplyParams; + bytes private _tokenTaxParams; + uint16 private _tokenMultiplier; // Unused + + bytes32 public constant BONDING_ROLE = keccak256("BONDING_ROLE"); + + /////////////////////////////////////////////////////////////// + + mapping(address => bool) private _existingAgents; + + error AgentAlreadyExists(); + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize( + address tokenImplementation_, + address veTokenImplementation_, + address daoImplementation_, + address tbaRegistry_, + address assetToken_, + address nft_, + uint256 applicationThreshold_, + address vault_, + uint256 nextId_ + ) public initializer { + __Pausable_init(); + + tokenImplementation = tokenImplementation_; + veTokenImplementation = veTokenImplementation_; + daoImplementation = daoImplementation_; + assetToken = assetToken_; + tbaRegistry = tbaRegistry_; + nft = nft_; + applicationThreshold = applicationThreshold_; + _nextId = nextId_; + _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 + ); + } + + function _executeApplication( + uint256 id, + bool canStake, + bytes memory tokenSupplyParams_, + bytes32 salt, + bool noLpStake + ) 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 + address token = _createNewAgentToken( + application.name, + application.symbol, + tokenSupplyParams_, + salt + ); + + // C2 + address lp = IAgentToken(token).liquidityPools()[0]; + IERC20(assetToken).safeTransfer(token, initialAmount); + IAgentToken(token).addInitialLiquidity(address(this)); + + // 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, + salt + ) + ); + + // 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 + if (noLpStake) { + // If not staking LP, send it to the Genesis contract + IERC20(lp).safeTransfer(msg.sender, IERC20(lp).balanceOf(address(this))); + } else { + 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); + } + + function executeApplication( + uint256 id, + bool canStake, + bytes32 salt, + bool noLpStake + ) 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, salt, noLpStake); + } + + function _createNewDAO( + string memory name, + IVotes token, + uint32 daoVotingPeriod, + uint256 daoThreshold, + bytes32 salt + ) internal returns (address instance) { + instance = Clones.cloneDeterministic(daoImplementation, salt); + if (_existingAgents[instance]) { + revert AgentAlreadyExists(); + } + IAgentDAO(instance).initialize( + name, + token, + nft, + daoThreshold, + daoVotingPeriod + ); + + allDAOs.push(instance); + return instance; + } + + function _createNewAgentToken( + string memory name, + string memory symbol, + bytes memory tokenSupplyParams_, + bytes32 salt + ) internal returns (address instance) { + instance = Clones.cloneDeterministic(tokenImplementation, salt); + if (_existingAgents[instance]) { + revert AgentAlreadyExists(); + } + _existingAgents[instance] = true; + 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 token, + address veToken, + address dao + ) public onlyRole(DEFAULT_ADMIN_ROLE) { + tokenImplementation = token; + daoImplementation = dao; + veTokenImplementation = veToken; + } + + function setParams( + uint256 newMaturityDuration, + address newRouter, + address newDelegatee, + address newTokenAdmin + ) public onlyRole(DEFAULT_ADMIN_ROLE) { + maturityDuration = newMaturityDuration; + _uniswapRouter = newRouter; + defaultDelegatee = newDelegatee; + _tokenAdmin = newTokenAdmin; + } + + function setTokenParams( + uint256 maxSupply, + uint256 lpSupply, + uint256 vaultSupply, + uint256 maxTokensPerWallet, + uint256 maxTokensPerTxn, + uint256 botProtectionDurationInSeconds, + address vault, + uint256 projectBuyTaxBasisPoints, + uint256 projectSellTaxBasisPoints, + uint256 taxSwapThresholdBasisPoints, + address projectTaxRecipient + ) public onlyRole(DEFAULT_ADMIN_ROLE) { + require((lpSupply + vaultSupply) <= maxSupply, "Invalid supply"); + _tokenSupplyParams = abi.encode( + maxSupply, + lpSupply, + vaultSupply, + maxTokensPerWallet, + maxTokensPerTxn, + botProtectionDurationInSeconds, + vault + ); + _tokenTaxParams = abi.encode( + projectBuyTaxBasisPoints, + projectSellTaxBasisPoints, + taxSwapThresholdBasisPoints, + projectTaxRecipient + ); + } + + function pause() public onlyRole(DEFAULT_ADMIN_ROLE) { + _pause(); + } + + function unpause() public onlyRole(DEFAULT_ADMIN_ROLE) { + _unpause(); + } + + function _msgSender() + internal + view + override(Context, ContextUpgradeable) + returns (address sender) + { + sender = ContextUpgradeable._msgSender(); + } + + function _msgData() + internal + view + override(Context, ContextUpgradeable) + returns (bytes calldata) + { + return ContextUpgradeable._msgData(); + } + + function initFromBondingCurve( + string memory name, + string memory symbol, + uint8[] memory cores, + bytes32 tbaSalt, + address tbaImplementation, + uint32 daoVotingPeriod, + uint256 daoThreshold, + uint256 applicationThreshold_, + address creator + ) public whenNotPaused onlyRole(BONDING_ROLE) 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, + "", + ApplicationStatus.Active, + applicationThreshold_, + creator, + cores, + proposalEndBlock, + 0, + tbaSalt, + tbaImplementation, + daoVotingPeriod, + daoThreshold + ); + _applications[id] = application; + emit NewApplication(id); + + return id; + } + + function executeBondingCurveApplicationSalt( + uint256 id, + uint256 totalSupply, + uint256 lpSupply, + address vault, + bytes32 salt, + bool noLpStake + ) public onlyRole(BONDING_ROLE) noReentrant returns (address) { + bytes memory tokenSupplyParams = abi.encode( + totalSupply, + lpSupply, + totalSupply - lpSupply, + totalSupply, + totalSupply, + 0, + vault + ); + + _executeApplication(id, true, tokenSupplyParams, salt, noLpStake); + + Application memory application = _applications[id]; + + return IAgentNft(nft).virtualInfo(application.virtualId).token; + } +} diff --git a/contracts/virtualPersona/IAgentFactoryV5.sol b/contracts/virtualPersona/IAgentFactoryV5.sol new file mode 100644 index 0000000..82a5e99 --- /dev/null +++ b/contracts/virtualPersona/IAgentFactoryV5.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import "@openzeppelin/contracts/governance/IGovernor.sol"; + +interface IAgentFactoryV5 { + 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 initFromBondingCurve( + string memory name, + string memory symbol, + uint8[] memory cores, + bytes32 tbaSalt, + address tbaImplementation, + uint32 daoVotingPeriod, + uint256 daoThreshold, + uint256 applicationThreshold_, + address creator + ) external returns (uint256); + + + function executeBondingCurveApplicationSalt( + uint256 id, + uint256 totalSupply, + uint256 lpSupply, + address vault, + bytes32 salt, + bool noLpStake + ) external returns (address); +} diff --git a/scripts/arguments/genesis/agentFactoryV5Arguments.js b/scripts/arguments/genesis/agentFactoryV5Arguments.js new file mode 100644 index 0000000..36d1d82 --- /dev/null +++ b/scripts/arguments/genesis/agentFactoryV5Arguments.js @@ -0,0 +1,11 @@ +module.exports = [ + process.env.VIRTUAL_TOKEN_IMPL, + process.env.VIRTUAL_VETOKEN_IMPL, + process.env.VIRTUAL_DAO_IMPL, + process.env.TBA, + process.env.BRIDGED_TOKEN, + process.env.VIRTUAL_NFT, + process.env.VIRTUAL_APPLICATION_THRESHOLD, + process.env.VIRTUAL_VAULT, + process.env.NEXT_ID, +]; diff --git a/scripts/arguments/fgenesis.js b/scripts/arguments/genesis/fgenesis.js similarity index 100% rename from scripts/arguments/fgenesis.js rename to scripts/arguments/genesis/fgenesis.js diff --git a/scripts/genesis/deployAgentFactoryV5.ts b/scripts/genesis/deployAgentFactoryV5.ts new file mode 100644 index 0000000..066a146 --- /dev/null +++ b/scripts/genesis/deployAgentFactoryV5.ts @@ -0,0 +1,59 @@ +import { parseEther } from "ethers"; +import { ethers, upgrades } from "hardhat"; + +const adminSigner = new ethers.Wallet( + process.env.ADMIN_PRIVATE_KEY, + ethers.provider +); + +(async () => { + try { + const args = require("../arguments/genesis/agentFactoryV5Arguments"); + const Contract = await ethers.getContractFactory("AgentFactoryV5"); + const contract = await upgrades.deployProxy(Contract, args, { + initialOwner: process.env.CONTRACT_CONTROLLER, + }); + console.log("AgentFactoryV5 deployed to:", contract.target); + + const t2 = await contract.setTokenParams( + process.env.AGENT_TOKEN_SUPPLY, + process.env.AGENT_TOKEN_LP_SUPPLY, + process.env.AGENT_TOKEN_VAULT_SUPPLY, + process.env.AGENT_TOKEN_LIMIT_WALLET, + process.env.AGENT_TOKEN_LIMIT_TRX, + process.env.BOT_PROTECTION, + process.env.MINTER, + process.env.TAX, + process.env.TAX, + process.env.SWAP_THRESHOLD, + process.env.TAX_VAULT + ); + await t2.wait(); + console.log("Token params set"); + + const t3 = await contract.setParams( + process.env.MATURITY_DURATION, + process.env.UNISWAP_ROUTER, + process.env.DELEGATEE, // unused + process.env.ADMIN + ); + await t3.wait(); + console.log("Params set"); + const t4 = await contract.grantRole( + await contract.WITHDRAW_ROLE(), + process.env.OP + ); + await t4.wait(); + console.log("Withdraw role granted"); + + const nft = await ethers.getContractAt( + "AgentNftV2", + process.env.VIRTUAL_NFT, + adminSigner + ); + await nft.grantRole(await nft.MINTER_ROLE(), contract.target); + console.log("Minter role granted"); + } catch (e) { + console.log(e); + } +})(); diff --git a/scripts/genesis/deployGenesis.ts b/scripts/genesis/deployGenesis.ts index bfe37bf..91258b2 100644 --- a/scripts/genesis/deployGenesis.ts +++ b/scripts/genesis/deployGenesis.ts @@ -27,7 +27,7 @@ import { ethers, upgrades } from "hardhat"; } // Load arguments from the arguments file - const args = require("../arguments/fgenesis"); + const args = require("../arguments/genesis/fgenesis"); // Create the params struct const params = { diff --git a/test/genesis/setup.js b/test/genesis/setup.js index 256b6dc..8fcfb53 100644 --- a/test/genesis/setup.js +++ b/test/genesis/setup.js @@ -1,7 +1,7 @@ const { expect } = require("chai"); const { ethers, upgrades } = require("hardhat"); const { time } = require("@nomicfoundation/hardhat-network-helpers"); -const fgenesis = require("../../scripts/arguments/fgenesis"); +const fgenesis = require("../../scripts/arguments/genesis/fgenesis"); async function setupTest() { // Return object to store all setup results @@ -285,7 +285,7 @@ async function setupTest() { ); console.log("\n=== Creating Genesis ==="); - const tx = await fGenesis.connect(beOpsWallet).createGenesis(genesisParams); + const tx = await fGenesis.connect(beOpsWallet).createGenesis(genesisParams, true); console.log("Genesis creation transaction sent"); const receipt = await tx.wait(); diff --git a/test/genesis/size.js b/test/genesis/size.js new file mode 100644 index 0000000..6a349d0 --- /dev/null +++ b/test/genesis/size.js @@ -0,0 +1,26 @@ +const { expect } = require("chai"); +const { ethers } = require("hardhat"); + +describe("Contract Size", function () { + it("Should be within size limits", async function () { + const Genesis = await ethers.getContractFactory("Genesis"); + const AgentFactoryV3 = await ethers.getContractFactory("AgentFactoryV3"); + const AgentFactoryV5 = await ethers.getContractFactory("AgentFactoryV5"); + const FGenesis = await ethers.getContractFactory("FGenesis"); + + const genesisSize = Genesis.bytecode.length / 2; + const fGenesisSize = FGenesis.bytecode.length / 2; + const agentFactoryV5Size = AgentFactoryV5.bytecode.length / 2; + const agentFactoryV3Size = AgentFactoryV3.bytecode.length / 2; + console.log('Genesis size:', genesisSize, 'bytes'); + console.log('FGenesis size:', fGenesisSize, 'bytes'); + console.log('AgentFactoryV5 size:', agentFactoryV5Size, 'bytes'); + console.log('AgentFactoryV3 size:', agentFactoryV3Size, 'bytes'); + + // 24576 is EVM contract size limit + expect(genesisSize).to.be.lessThan(24576, "Genesis contract too large"); + expect(fGenesisSize).to.be.lessThan(24576, "FGenesis contract too large"); + expect(agentFactoryV5Size).to.be.lessThan(24576, "AgentFactoryV5 contract too large"); + expect(agentFactoryV3Size).to.be.lessThan(24576, "AgentFactoryV3 contract too large"); + }); +}); \ No newline at end of file