diff --git a/.gitignore b/.gitignore index cc46584..9209bd7 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,5 @@ diagrams/* echidna/results/* .DS_Store echidna/results -diagrams/ \ No newline at end of file +diagrams/ +.openzeppelin/unknown-666666.json diff --git a/.openzeppelin/unknown-9001.json b/.openzeppelin/unknown-9001.json index b0224ff..2e512bf 100644 --- a/.openzeppelin/unknown-9001.json +++ b/.openzeppelin/unknown-9001.json @@ -320,7 +320,7 @@ "label": "_roles", "offset": 0, "slot": "51", - "type": "t_contract(DAORoles)11779", + "type": "t_contract(DAORoles)8840", "contract": "HasRole", "src": "contracts/extensions/HasRole.sol:11" }, @@ -376,7 +376,7 @@ "label": "_voting", "offset": 0, "slot": "102", - "type": "t_contract(IVoting)10726", + "type": "t_contract(IVoting)8824", "contract": "GovernanceTokenBase", "src": "contracts/GovernanceToken/GovernanceTokenBase.sol:15" }, @@ -384,7 +384,7 @@ "label": "_redemptionController", "offset": 0, "slot": "103", - "type": "t_contract(IRedemptionController)7404", + "type": "t_contract(IRedemptionController)7060", "contract": "GovernanceTokenBase", "src": "contracts/GovernanceToken/GovernanceTokenBase.sol:16" }, @@ -392,7 +392,7 @@ "label": "tokenExternal", "offset": 0, "slot": "104", - "type": "t_contract(INeokingdomToken)7046", + "type": "t_contract(INeokingdomToken)6992", "contract": "GovernanceTokenBase", "src": "contracts/GovernanceToken/GovernanceTokenBase.sol:17" }, @@ -416,7 +416,7 @@ "label": "_accountBalanceSnapshots", "offset": 0, "slot": "107", - "type": "t_mapping(t_address,t_struct(Snapshots)5744_storage)", + "type": "t_mapping(t_address,t_struct(Snapshots)5700_storage)", "contract": "GovernanceTokenSnapshot", "src": "contracts/GovernanceToken/GovernanceTokenSnapshot.sol:21" }, @@ -424,7 +424,7 @@ "label": "_totalSupplySnapshots", "offset": 0, "slot": "108", - "type": "t_struct(Snapshots)5744_storage", + "type": "t_struct(Snapshots)5700_storage", "contract": "GovernanceTokenSnapshot", "src": "contracts/GovernanceToken/GovernanceTokenSnapshot.sol:22" } @@ -450,19 +450,19 @@ "label": "bool", "numberOfBytes": "1" }, - "t_contract(DAORoles)11779": { + "t_contract(DAORoles)8840": { "label": "contract DAORoles", "numberOfBytes": "20" }, - "t_contract(INeokingdomToken)7046": { + "t_contract(INeokingdomToken)6992": { "label": "contract INeokingdomToken", "numberOfBytes": "20" }, - "t_contract(IRedemptionController)7404": { + "t_contract(IRedemptionController)7060": { "label": "contract IRedemptionController", "numberOfBytes": "20" }, - "t_contract(IVoting)10726": { + "t_contract(IVoting)8824": { "label": "contract IVoting", "numberOfBytes": "20" }, @@ -470,7 +470,7 @@ "label": "mapping(address => mapping(address => uint256))", "numberOfBytes": "32" }, - "t_mapping(t_address,t_struct(Snapshots)5744_storage)": { + "t_mapping(t_address,t_struct(Snapshots)5700_storage)": { "label": "mapping(address => struct GovernanceTokenSnapshot.Snapshots)", "numberOfBytes": "32" }, @@ -482,7 +482,7 @@ "label": "string", "numberOfBytes": "32" }, - "t_struct(Snapshots)5744_storage": { + "t_struct(Snapshots)5700_storage": { "label": "struct GovernanceTokenSnapshot.Snapshots", "members": [ { @@ -1818,7 +1818,7 @@ "label": "_roles", "offset": 0, "slot": "51", - "type": "t_contract(DAORoles)5493", + "type": "t_contract(DAORoles)7289", "contract": "HasRole", "src": "contracts/extensions/HasRole.sol:11" }, @@ -1826,7 +1826,7 @@ "label": "tokenInternal", "offset": 0, "slot": "52", - "type": "t_contract(IGovernanceToken)4309", + "type": "t_contract(IGovernanceToken)6008", "contract": "InternalMarketBase", "src": "contracts/InternalMarket/InternalMarketBase.sol:34" }, @@ -1834,7 +1834,7 @@ "label": "exchangeToken", "offset": 0, "slot": "53", - "type": "t_contract(ERC20)3053", + "type": "t_contract(ERC20)3690", "contract": "InternalMarketBase", "src": "contracts/InternalMarket/InternalMarketBase.sol:37" }, @@ -1842,7 +1842,7 @@ "label": "redemptionController", "offset": 0, "slot": "54", - "type": "t_contract(IRedemptionController)5387", + "type": "t_contract(IRedemptionController)7086", "contract": "InternalMarketBase", "src": "contracts/InternalMarket/InternalMarketBase.sol:39" }, @@ -1850,7 +1850,7 @@ "label": "priceOracle", "offset": 0, "slot": "55", - "type": "t_contract(IStdReference)5354", + "type": "t_contract(IStdReference)7053", "contract": "InternalMarketBase", "src": "contracts/InternalMarket/InternalMarketBase.sol:40" }, @@ -1858,7 +1858,7 @@ "label": "_shareholderRegistry", "offset": 0, "slot": "56", - "type": "t_contract(IShareholderRegistry)5477", + "type": "t_contract(IShareholderRegistry)7176", "contract": "InternalMarketBase", "src": "contracts/InternalMarket/InternalMarketBase.sol:41" }, @@ -1882,7 +1882,7 @@ "label": "_offers", "offset": 0, "slot": "59", - "type": "t_mapping(t_address,t_struct(Offers)4556_storage)", + "type": "t_mapping(t_address,t_struct(Offers)6255_storage)", "contract": "InternalMarketBase", "src": "contracts/InternalMarket/InternalMarketBase.sol:46" }, @@ -1908,31 +1908,31 @@ "label": "bool", "numberOfBytes": "1" }, - "t_contract(DAORoles)5493": { + "t_contract(DAORoles)7289": { "label": "contract DAORoles", "numberOfBytes": "20" }, - "t_contract(ERC20)3053": { + "t_contract(ERC20)3690": { "label": "contract ERC20", "numberOfBytes": "20" }, - "t_contract(IGovernanceToken)4309": { + "t_contract(IGovernanceToken)6008": { "label": "contract IGovernanceToken", "numberOfBytes": "20" }, - "t_contract(IRedemptionController)5387": { + "t_contract(IRedemptionController)7086": { "label": "contract IRedemptionController", "numberOfBytes": "20" }, - "t_contract(IShareholderRegistry)5477": { + "t_contract(IShareholderRegistry)7176": { "label": "contract IShareholderRegistry", "numberOfBytes": "20" }, - "t_contract(IStdReference)5354": { + "t_contract(IStdReference)7053": { "label": "contract IStdReference", "numberOfBytes": "20" }, - "t_mapping(t_address,t_struct(Offers)4556_storage)": { + "t_mapping(t_address,t_struct(Offers)6255_storage)": { "label": "mapping(address => struct InternalMarketBase.Offers)", "numberOfBytes": "32" }, @@ -1940,11 +1940,11 @@ "label": "mapping(address => uint256)", "numberOfBytes": "32" }, - "t_mapping(t_uint128,t_struct(Offer)4546_storage)": { + "t_mapping(t_uint128,t_struct(Offer)6245_storage)": { "label": "mapping(uint128 => struct InternalMarketBase.Offer)", "numberOfBytes": "32" }, - "t_struct(Offer)4546_storage": { + "t_struct(Offer)6245_storage": { "label": "struct InternalMarketBase.Offer", "members": [ { @@ -1962,7 +1962,7 @@ ], "numberOfBytes": "64" }, - "t_struct(Offers)4556_storage": { + "t_struct(Offers)6255_storage": { "label": "struct InternalMarketBase.Offers", "members": [ { @@ -1979,7 +1979,7 @@ }, { "label": "offer", - "type": "t_mapping(t_uint128,t_struct(Offer)4546_storage)", + "type": "t_mapping(t_uint128,t_struct(Offer)6245_storage)", "offset": 0, "slot": "1" } @@ -2436,6 +2436,1516 @@ } } } + }, + "6398dc6f59d82dd0b92d4fce1a06916c7755c65675ffdc12d26259320d85cbf3": { + "address": "0x21bc56fa89902Ad945413Ed606AfC1Fd8c22fBE2", + "txHash": "0xc9f08f2c51a2ba1101f7a5b4a0f2cb9b335202fb19d062e065ee1a6631f0465c", + "layout": { + "solcVersion": "0.8.19", + "storage": [ + { + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62", + "retypedFrom": "bool" + }, + { + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "ContextUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" + }, + { + "label": "_roles", + "offset": 0, + "slot": "51", + "type": "t_contract(DAORoles)7607", + "contract": "HasRole", + "src": "contracts/extensions/HasRole.sol:11" + }, + { + "label": "_balances", + "offset": 0, + "slot": "52", + "type": "t_mapping(t_address,t_uint256)", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:37" + }, + { + "label": "_allowances", + "offset": 0, + "slot": "53", + "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:39" + }, + { + "label": "_totalSupply", + "offset": 0, + "slot": "54", + "type": "t_uint256", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:41" + }, + { + "label": "_name", + "offset": 0, + "slot": "55", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:43" + }, + { + "label": "_symbol", + "offset": 0, + "slot": "56", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:44" + }, + { + "label": "__gap", + "offset": 0, + "slot": "57", + "type": "t_array(t_uint256)45_storage", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:400" + }, + { + "label": "_voting", + "offset": 0, + "slot": "102", + "type": "t_contract(IVoting)7591", + "contract": "GovernanceTokenBase", + "src": "contracts/GovernanceToken/GovernanceTokenBase.sol:15" + }, + { + "label": "_redemptionController", + "offset": 0, + "slot": "103", + "type": "t_contract(IRedemptionController)7397", + "contract": "GovernanceTokenBase", + "src": "contracts/GovernanceToken/GovernanceTokenBase.sol:16" + }, + { + "label": "tokenExternal", + "offset": 0, + "slot": "104", + "type": "t_contract(INeokingdomToken)7364", + "contract": "GovernanceTokenBase", + "src": "contracts/GovernanceToken/GovernanceTokenBase.sol:17" + }, + { + "label": "_vestingBalance", + "offset": 0, + "slot": "105", + "type": "t_mapping(t_address,t_uint256)", + "contract": "GovernanceTokenBase", + "src": "contracts/GovernanceToken/GovernanceTokenBase.sol:28" + }, + { + "label": "_currentSnapshotId", + "offset": 0, + "slot": "106", + "type": "t_uint256", + "contract": "Snapshottable", + "src": "contracts/extensions/Snapshottable.sol:11" + }, + { + "label": "_accountBalanceSnapshots", + "offset": 0, + "slot": "107", + "type": "t_mapping(t_address,t_struct(Snapshots)5954_storage)", + "contract": "GovernanceTokenSnapshot", + "src": "contracts/GovernanceToken/GovernanceTokenSnapshot.sol:21" + }, + { + "label": "_totalSupplySnapshots", + "offset": 0, + "slot": "108", + "type": "t_struct(Snapshots)5954_storage", + "contract": "GovernanceTokenSnapshot", + "src": "contracts/GovernanceToken/GovernanceTokenSnapshot.sol:22" + }, + { + "label": "_shareholderRegistry", + "offset": 0, + "slot": "110", + "type": "t_contract(IShareholderRegistry)7494", + "contract": "GovernanceToken", + "src": "contracts/GovernanceToken/GovernanceToken.sol:20" + }, + { + "label": "depositedTokens", + "offset": 0, + "slot": "111", + "type": "t_mapping(t_address,t_array(t_struct(DepositedTokens)5139_storage)dyn_storage)", + "contract": "GovernanceToken", + "src": "contracts/GovernanceToken/GovernanceToken.sol:33" + }, + { + "label": "settlementPeriod", + "offset": 0, + "slot": "112", + "type": "t_uint256", + "contract": "GovernanceToken", + "src": "contracts/GovernanceToken/GovernanceToken.sol:35" + } + ], + "types": { + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(DepositedTokens)5139_storage)dyn_storage": { + "label": "struct GovernanceToken.DepositedTokens[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)45_storage": { + "label": "uint256[45]", + "numberOfBytes": "1440" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_array(t_uint256)dyn_storage": { + "label": "uint256[]", + "numberOfBytes": "32" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_contract(DAORoles)7607": { + "label": "contract DAORoles", + "numberOfBytes": "20" + }, + "t_contract(INeokingdomToken)7364": { + "label": "contract INeokingdomToken", + "numberOfBytes": "20" + }, + "t_contract(IRedemptionController)7397": { + "label": "contract IRedemptionController", + "numberOfBytes": "20" + }, + "t_contract(IShareholderRegistry)7494": { + "label": "contract IShareholderRegistry", + "numberOfBytes": "20" + }, + "t_contract(IVoting)7591": { + "label": "contract IVoting", + "numberOfBytes": "20" + }, + "t_mapping(t_address,t_array(t_struct(DepositedTokens)5139_storage)dyn_storage)": { + "label": "mapping(address => struct GovernanceToken.DepositedTokens[])", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_mapping(t_address,t_uint256))": { + "label": "mapping(address => mapping(address => uint256))", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_struct(Snapshots)5954_storage)": { + "label": "mapping(address => struct GovernanceTokenSnapshot.Snapshots)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_string_storage": { + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(DepositedTokens)5139_storage": { + "label": "struct GovernanceToken.DepositedTokens", + "members": [ + { + "label": "amount", + "type": "t_uint256", + "offset": 0, + "slot": "0" + }, + { + "label": "settlementTimestamp", + "type": "t_uint256", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_struct(Snapshots)5954_storage": { + "label": "struct GovernanceTokenSnapshot.Snapshots", + "members": [ + { + "label": "ids", + "type": "t_array(t_uint256)dyn_storage", + "offset": 0, + "slot": "0" + }, + { + "label": "values", + "type": "t_array(t_uint256)dyn_storage", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + } + } + }, + "c73d13ac4ac873d8b92b5d3dffcf795df2ca1358685de9b3bf6f16f6c5a4034e": { + "address": "0xEDDF3b7810ca9DfB32E6a3E275e635987904450e", + "txHash": "0x9b51312c78ab51249241f0ace0ed820bee04a5a96dbd60b63bb0ea27a21bd2de", + "layout": { + "solcVersion": "0.8.19", + "storage": [ + { + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62", + "retypedFrom": "bool" + }, + { + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "ContextUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" + }, + { + "label": "_roles", + "offset": 0, + "slot": "51", + "type": "t_contract(DAORoles)13255", + "contract": "HasRole", + "src": "contracts/extensions/HasRole.sol:11" + }, + { + "label": "tokenInternal", + "offset": 0, + "slot": "52", + "type": "t_contract(IGovernanceToken)7303", + "contract": "InternalMarketBase", + "src": "contracts/InternalMarket/InternalMarketBase.sol:34" + }, + { + "label": "exchangeToken", + "offset": 0, + "slot": "53", + "type": "t_contract(ERC20)4378", + "contract": "InternalMarketBase", + "src": "contracts/InternalMarket/InternalMarketBase.sol:37" + }, + { + "label": "redemptionController", + "offset": 0, + "slot": "54", + "type": "t_contract(IRedemptionController)8761", + "contract": "InternalMarketBase", + "src": "contracts/InternalMarket/InternalMarketBase.sol:39" + }, + { + "label": "priceOracle", + "offset": 0, + "slot": "55", + "type": "t_contract(IStdReference)8489", + "contract": "InternalMarketBase", + "src": "contracts/InternalMarket/InternalMarketBase.sol:40" + }, + { + "label": "_shareholderRegistry", + "offset": 0, + "slot": "56", + "type": "t_contract(IShareholderRegistry)11142", + "contract": "InternalMarketBase", + "src": "contracts/InternalMarket/InternalMarketBase.sol:41" + }, + { + "label": "reserve", + "offset": 0, + "slot": "57", + "type": "t_address", + "contract": "InternalMarketBase", + "src": "contracts/InternalMarket/InternalMarketBase.sol:43" + }, + { + "label": "offerDuration", + "offset": 0, + "slot": "58", + "type": "t_uint256", + "contract": "InternalMarketBase", + "src": "contracts/InternalMarket/InternalMarketBase.sol:44" + }, + { + "label": "_offers", + "offset": 0, + "slot": "59", + "type": "t_mapping(t_address,t_struct(Offers)7625_storage)", + "contract": "InternalMarketBase", + "src": "contracts/InternalMarket/InternalMarketBase.sol:46" + }, + { + "label": "_vaultContributors", + "offset": 0, + "slot": "60", + "type": "t_mapping(t_address,t_uint256)", + "contract": "InternalMarketBase", + "src": "contracts/InternalMarket/InternalMarketBase.sol:48" + } + ], + "types": { + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_contract(DAORoles)13255": { + "label": "contract DAORoles", + "numberOfBytes": "20" + }, + "t_contract(ERC20)4378": { + "label": "contract ERC20", + "numberOfBytes": "20" + }, + "t_contract(IGovernanceToken)7303": { + "label": "contract IGovernanceToken", + "numberOfBytes": "20" + }, + "t_contract(IRedemptionController)8761": { + "label": "contract IRedemptionController", + "numberOfBytes": "20" + }, + "t_contract(IShareholderRegistry)11142": { + "label": "contract IShareholderRegistry", + "numberOfBytes": "20" + }, + "t_contract(IStdReference)8489": { + "label": "contract IStdReference", + "numberOfBytes": "20" + }, + "t_mapping(t_address,t_struct(Offers)7625_storage)": { + "label": "mapping(address => struct InternalMarketBase.Offers)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_uint128,t_struct(Offer)7615_storage)": { + "label": "mapping(uint128 => struct InternalMarketBase.Offer)", + "numberOfBytes": "32" + }, + "t_struct(Offer)7615_storage": { + "label": "struct InternalMarketBase.Offer", + "members": [ + { + "label": "expiredAt", + "type": "t_uint256", + "offset": 0, + "slot": "0" + }, + { + "label": "amount", + "type": "t_uint256", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_struct(Offers)7625_storage": { + "label": "struct InternalMarketBase.Offers", + "members": [ + { + "label": "start", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "end", + "type": "t_uint128", + "offset": 16, + "slot": "0" + }, + { + "label": "offer", + "type": "t_mapping(t_uint128,t_struct(Offer)7615_storage)", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + } + } + }, + "0b3621572808727f4a9449fa76563140af8313ccb9b2a1b871e2bf39371370ec": { + "address": "0x21b4A54A0B457f1C488CBB989bD221C283A42c19", + "txHash": "0x1f8596c52bb6d5ea3345bcb70de05a2624a3bebe5cbf231256477519fbffe885", + "layout": { + "solcVersion": "0.8.19", + "storage": [ + { + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62", + "retypedFrom": "bool" + }, + { + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "ContextUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" + }, + { + "label": "_roles", + "offset": 0, + "slot": "51", + "type": "t_contract(DAORoles)13019", + "contract": "HasRole", + "src": "contracts/extensions/HasRole.sol:11" + }, + { + "label": "tokenInternal", + "offset": 0, + "slot": "52", + "type": "t_contract(IGovernanceToken)7303", + "contract": "InternalMarketBase", + "src": "contracts/InternalMarket/InternalMarketBase.sol:33" + }, + { + "label": "exchangeToken", + "offset": 0, + "slot": "53", + "type": "t_contract(ERC20)4378", + "contract": "InternalMarketBase", + "src": "contracts/InternalMarket/InternalMarketBase.sol:36" + }, + { + "label": "redemptionController", + "offset": 0, + "slot": "54", + "type": "t_contract(IRedemptionController)8525", + "contract": "InternalMarketBase", + "src": "contracts/InternalMarket/InternalMarketBase.sol:38" + }, + { + "label": "priceOracle", + "offset": 0, + "slot": "55", + "type": "t_contract(IDIAOracleV2)7329", + "contract": "InternalMarketBase", + "src": "contracts/InternalMarket/InternalMarketBase.sol:39" + }, + { + "label": "_shareholderRegistry", + "offset": 0, + "slot": "56", + "type": "t_contract(IShareholderRegistry)10906", + "contract": "InternalMarketBase", + "src": "contracts/InternalMarket/InternalMarketBase.sol:40" + }, + { + "label": "reserve", + "offset": 0, + "slot": "57", + "type": "t_address", + "contract": "InternalMarketBase", + "src": "contracts/InternalMarket/InternalMarketBase.sol:42" + }, + { + "label": "offerDuration", + "offset": 0, + "slot": "58", + "type": "t_uint256", + "contract": "InternalMarketBase", + "src": "contracts/InternalMarket/InternalMarketBase.sol:43" + }, + { + "label": "_offers", + "offset": 0, + "slot": "59", + "type": "t_mapping(t_address,t_struct(Offers)7667_storage)", + "contract": "InternalMarketBase", + "src": "contracts/InternalMarket/InternalMarketBase.sol:45" + }, + { + "label": "_vaultContributors", + "offset": 0, + "slot": "60", + "type": "t_mapping(t_address,t_uint256)", + "contract": "InternalMarketBase", + "src": "contracts/InternalMarket/InternalMarketBase.sol:47" + }, + { + "label": "_diaPriceOracle", + "offset": 0, + "slot": "61", + "type": "t_contract(IDIAOracleV2)7329", + "contract": "InternalMarket", + "src": "contracts/InternalMarket/InternalMarket.sol:21" + } + ], + "types": { + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_contract(DAORoles)13019": { + "label": "contract DAORoles", + "numberOfBytes": "20" + }, + "t_contract(ERC20)4378": { + "label": "contract ERC20", + "numberOfBytes": "20" + }, + "t_contract(IDIAOracleV2)7329": { + "label": "contract IDIAOracleV2", + "numberOfBytes": "20" + }, + "t_contract(IGovernanceToken)7303": { + "label": "contract IGovernanceToken", + "numberOfBytes": "20" + }, + "t_contract(IRedemptionController)8525": { + "label": "contract IRedemptionController", + "numberOfBytes": "20" + }, + "t_contract(IShareholderRegistry)10906": { + "label": "contract IShareholderRegistry", + "numberOfBytes": "20" + }, + "t_mapping(t_address,t_struct(Offers)7667_storage)": { + "label": "mapping(address => struct InternalMarketBase.Offers)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_uint128,t_struct(Offer)7657_storage)": { + "label": "mapping(uint128 => struct InternalMarketBase.Offer)", + "numberOfBytes": "32" + }, + "t_struct(Offer)7657_storage": { + "label": "struct InternalMarketBase.Offer", + "members": [ + { + "label": "expiredAt", + "type": "t_uint256", + "offset": 0, + "slot": "0" + }, + { + "label": "amount", + "type": "t_uint256", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_struct(Offers)7667_storage": { + "label": "struct InternalMarketBase.Offers", + "members": [ + { + "label": "start", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "end", + "type": "t_uint128", + "offset": 16, + "slot": "0" + }, + { + "label": "offer", + "type": "t_mapping(t_uint128,t_struct(Offer)7657_storage)", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + } + } + }, + "fc8fccb6beac0421dda67147bbd35e89507ac4d5ab04bfaa9db6a19473f05fd8": { + "address": "0xA64A0B84da74e559E4fD2d05aEAA6582121D7FD7", + "txHash": "0xb60b93105c9a75906b511bfcdd2c3fc8ee893cfc466dfbbc0783dc7cf05777a4", + "layout": { + "solcVersion": "0.8.19", + "storage": [ + { + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62", + "retypedFrom": "bool" + }, + { + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "ContextUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" + }, + { + "label": "_roles", + "offset": 0, + "slot": "51", + "type": "t_contract(DAORoles)13007", + "contract": "HasRole", + "src": "contracts/extensions/HasRole.sol:11" + }, + { + "label": "tokenInternal", + "offset": 0, + "slot": "52", + "type": "t_contract(IGovernanceToken)7303", + "contract": "InternalMarketBase", + "src": "contracts/InternalMarket/InternalMarketBase.sol:33" + }, + { + "label": "exchangeToken", + "offset": 0, + "slot": "53", + "type": "t_contract(ERC20)4378", + "contract": "InternalMarketBase", + "src": "contracts/InternalMarket/InternalMarketBase.sol:36" + }, + { + "label": "redemptionController", + "offset": 0, + "slot": "54", + "type": "t_contract(IRedemptionController)8513", + "contract": "InternalMarketBase", + "src": "contracts/InternalMarket/InternalMarketBase.sol:38" + }, + { + "label": "priceOracle", + "offset": 0, + "slot": "55", + "type": "t_contract(IDIAOracleV2)7329", + "contract": "InternalMarketBase", + "src": "contracts/InternalMarket/InternalMarketBase.sol:39" + }, + { + "label": "_shareholderRegistry", + "offset": 0, + "slot": "56", + "type": "t_contract(IShareholderRegistry)10894", + "contract": "InternalMarketBase", + "src": "contracts/InternalMarket/InternalMarketBase.sol:40" + }, + { + "label": "reserve", + "offset": 0, + "slot": "57", + "type": "t_address", + "contract": "InternalMarketBase", + "src": "contracts/InternalMarket/InternalMarketBase.sol:42" + }, + { + "label": "offerDuration", + "offset": 0, + "slot": "58", + "type": "t_uint256", + "contract": "InternalMarketBase", + "src": "contracts/InternalMarket/InternalMarketBase.sol:43" + }, + { + "label": "_offers", + "offset": 0, + "slot": "59", + "type": "t_mapping(t_address,t_struct(Offers)7655_storage)", + "contract": "InternalMarketBase", + "src": "contracts/InternalMarket/InternalMarketBase.sol:45" + }, + { + "label": "_vaultContributors", + "offset": 0, + "slot": "60", + "type": "t_mapping(t_address,t_uint256)", + "contract": "InternalMarketBase", + "src": "contracts/InternalMarket/InternalMarketBase.sol:47" + }, + { + "label": "_diaPriceOracle", + "offset": 0, + "slot": "61", + "type": "t_contract(IDIAOracleV2)7329", + "contract": "InternalMarket", + "src": "contracts/InternalMarket/InternalMarket.sol:21" + } + ], + "types": { + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_contract(DAORoles)13007": { + "label": "contract DAORoles", + "numberOfBytes": "20" + }, + "t_contract(ERC20)4378": { + "label": "contract ERC20", + "numberOfBytes": "20" + }, + "t_contract(IDIAOracleV2)7329": { + "label": "contract IDIAOracleV2", + "numberOfBytes": "20" + }, + "t_contract(IGovernanceToken)7303": { + "label": "contract IGovernanceToken", + "numberOfBytes": "20" + }, + "t_contract(IRedemptionController)8513": { + "label": "contract IRedemptionController", + "numberOfBytes": "20" + }, + "t_contract(IShareholderRegistry)10894": { + "label": "contract IShareholderRegistry", + "numberOfBytes": "20" + }, + "t_mapping(t_address,t_struct(Offers)7655_storage)": { + "label": "mapping(address => struct InternalMarketBase.Offers)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_uint128,t_struct(Offer)7645_storage)": { + "label": "mapping(uint128 => struct InternalMarketBase.Offer)", + "numberOfBytes": "32" + }, + "t_struct(Offer)7645_storage": { + "label": "struct InternalMarketBase.Offer", + "members": [ + { + "label": "expiredAt", + "type": "t_uint256", + "offset": 0, + "slot": "0" + }, + { + "label": "amount", + "type": "t_uint256", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_struct(Offers)7655_storage": { + "label": "struct InternalMarketBase.Offers", + "members": [ + { + "label": "start", + "type": "t_uint128", + "offset": 0, + "slot": "0" + }, + { + "label": "end", + "type": "t_uint128", + "offset": 16, + "slot": "0" + }, + { + "label": "offer", + "type": "t_mapping(t_uint128,t_struct(Offer)7645_storage)", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_uint128": { + "label": "uint128", + "numberOfBytes": "16" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + } + } + }, + "8f84054f22cda16e676faba845b0dc14336134dee5ff01b1ac755874f1f8ffa0": { + "address": "0xF28797507FA95A2A093dE9484F5c2E56Ad1b0585", + "txHash": "0x8b227b514473a5039593aafb8a1915f80bb43ae7a154136c6f79abf59e5d7f1e", + "layout": { + "solcVersion": "0.8.19", + "storage": [ + { + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62", + "retypedFrom": "bool" + }, + { + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "ContextUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" + }, + { + "label": "_roles", + "offset": 0, + "slot": "51", + "type": "t_contract(DAORoles)7625", + "contract": "HasRole", + "src": "contracts/extensions/HasRole.sol:11" + }, + { + "label": "_balances", + "offset": 0, + "slot": "52", + "type": "t_mapping(t_address,t_uint256)", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:37" + }, + { + "label": "_allowances", + "offset": 0, + "slot": "53", + "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:39" + }, + { + "label": "_totalSupply", + "offset": 0, + "slot": "54", + "type": "t_uint256", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:41" + }, + { + "label": "_name", + "offset": 0, + "slot": "55", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:43" + }, + { + "label": "_symbol", + "offset": 0, + "slot": "56", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:44" + }, + { + "label": "__gap", + "offset": 0, + "slot": "57", + "type": "t_array(t_uint256)45_storage", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:400" + }, + { + "label": "_voting", + "offset": 0, + "slot": "102", + "type": "t_contract(IVoting)7609", + "contract": "GovernanceTokenBase", + "src": "contracts/GovernanceToken/GovernanceTokenBase.sol:15" + }, + { + "label": "_redemptionController", + "offset": 0, + "slot": "103", + "type": "t_contract(IRedemptionController)7415", + "contract": "GovernanceTokenBase", + "src": "contracts/GovernanceToken/GovernanceTokenBase.sol:16" + }, + { + "label": "tokenExternal", + "offset": 0, + "slot": "104", + "type": "t_contract(INeokingdomToken)7382", + "contract": "GovernanceTokenBase", + "src": "contracts/GovernanceToken/GovernanceTokenBase.sol:17" + }, + { + "label": "_vestingBalance", + "offset": 0, + "slot": "105", + "type": "t_mapping(t_address,t_uint256)", + "contract": "GovernanceTokenBase", + "src": "contracts/GovernanceToken/GovernanceTokenBase.sol:28" + }, + { + "label": "_currentSnapshotId", + "offset": 0, + "slot": "106", + "type": "t_uint256", + "contract": "Snapshottable", + "src": "contracts/extensions/Snapshottable.sol:11" + }, + { + "label": "_accountBalanceSnapshots", + "offset": 0, + "slot": "107", + "type": "t_mapping(t_address,t_struct(Snapshots)5972_storage)", + "contract": "GovernanceTokenSnapshot", + "src": "contracts/GovernanceToken/GovernanceTokenSnapshot.sol:21" + }, + { + "label": "_totalSupplySnapshots", + "offset": 0, + "slot": "108", + "type": "t_struct(Snapshots)5972_storage", + "contract": "GovernanceTokenSnapshot", + "src": "contracts/GovernanceToken/GovernanceTokenSnapshot.sol:22" + }, + { + "label": "_shareholderRegistry", + "offset": 0, + "slot": "110", + "type": "t_contract(IShareholderRegistry)7512", + "contract": "GovernanceToken", + "src": "contracts/GovernanceToken/GovernanceToken.sol:20" + }, + { + "label": "depositedTokens", + "offset": 0, + "slot": "111", + "type": "t_mapping(t_address,t_array(t_struct(DepositedTokens)5139_storage)dyn_storage)", + "contract": "GovernanceToken", + "src": "contracts/GovernanceToken/GovernanceToken.sol:33" + }, + { + "label": "settlementPeriod", + "offset": 0, + "slot": "112", + "type": "t_uint256", + "contract": "GovernanceToken", + "src": "contracts/GovernanceToken/GovernanceToken.sol:35" + } + ], + "types": { + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(DepositedTokens)5139_storage)dyn_storage": { + "label": "struct GovernanceToken.DepositedTokens[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)45_storage": { + "label": "uint256[45]", + "numberOfBytes": "1440" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_array(t_uint256)dyn_storage": { + "label": "uint256[]", + "numberOfBytes": "32" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_contract(DAORoles)7625": { + "label": "contract DAORoles", + "numberOfBytes": "20" + }, + "t_contract(INeokingdomToken)7382": { + "label": "contract INeokingdomToken", + "numberOfBytes": "20" + }, + "t_contract(IRedemptionController)7415": { + "label": "contract IRedemptionController", + "numberOfBytes": "20" + }, + "t_contract(IShareholderRegistry)7512": { + "label": "contract IShareholderRegistry", + "numberOfBytes": "20" + }, + "t_contract(IVoting)7609": { + "label": "contract IVoting", + "numberOfBytes": "20" + }, + "t_mapping(t_address,t_array(t_struct(DepositedTokens)5139_storage)dyn_storage)": { + "label": "mapping(address => struct GovernanceToken.DepositedTokens[])", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_mapping(t_address,t_uint256))": { + "label": "mapping(address => mapping(address => uint256))", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_struct(Snapshots)5972_storage)": { + "label": "mapping(address => struct GovernanceTokenSnapshot.Snapshots)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_string_storage": { + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(DepositedTokens)5139_storage": { + "label": "struct GovernanceToken.DepositedTokens", + "members": [ + { + "label": "amount", + "type": "t_uint256", + "offset": 0, + "slot": "0" + }, + { + "label": "settlementTimestamp", + "type": "t_uint256", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_struct(Snapshots)5972_storage": { + "label": "struct GovernanceTokenSnapshot.Snapshots", + "members": [ + { + "label": "ids", + "type": "t_array(t_uint256)dyn_storage", + "offset": 0, + "slot": "0" + }, + { + "label": "values", + "type": "t_array(t_uint256)dyn_storage", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + } + } + }, + "246342d7309e3de8809de3d5caa182c103f09298ba3c3d554f7b1920d947b1df": { + "address": "0x0Dd55104F3462f54229672B2027bf74efd732fEB", + "txHash": "0xe961e9a203ed8cd95f96578be128ef5000a6e16dc31cdc233f0b5be21844a766", + "layout": { + "solcVersion": "0.8.19", + "storage": [ + { + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62", + "retypedFrom": "bool" + }, + { + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "ContextUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" + }, + { + "label": "_roles", + "offset": 0, + "slot": "51", + "type": "t_contract(DAORoles)7607", + "contract": "HasRole", + "src": "contracts/extensions/HasRole.sol:11" + }, + { + "label": "_balances", + "offset": 0, + "slot": "52", + "type": "t_mapping(t_address,t_uint256)", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:37" + }, + { + "label": "_allowances", + "offset": 0, + "slot": "53", + "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:39" + }, + { + "label": "_totalSupply", + "offset": 0, + "slot": "54", + "type": "t_uint256", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:41" + }, + { + "label": "_name", + "offset": 0, + "slot": "55", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:43" + }, + { + "label": "_symbol", + "offset": 0, + "slot": "56", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:44" + }, + { + "label": "__gap", + "offset": 0, + "slot": "57", + "type": "t_array(t_uint256)45_storage", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:400" + }, + { + "label": "_voting", + "offset": 0, + "slot": "102", + "type": "t_contract(IVoting)7591", + "contract": "GovernanceTokenBase", + "src": "contracts/GovernanceToken/GovernanceTokenBase.sol:15" + }, + { + "label": "_redemptionController", + "offset": 0, + "slot": "103", + "type": "t_contract(IRedemptionController)7397", + "contract": "GovernanceTokenBase", + "src": "contracts/GovernanceToken/GovernanceTokenBase.sol:16" + }, + { + "label": "tokenExternal", + "offset": 0, + "slot": "104", + "type": "t_contract(INeokingdomToken)7364", + "contract": "GovernanceTokenBase", + "src": "contracts/GovernanceToken/GovernanceTokenBase.sol:17" + }, + { + "label": "_vestingBalance", + "offset": 0, + "slot": "105", + "type": "t_mapping(t_address,t_uint256)", + "contract": "GovernanceTokenBase", + "src": "contracts/GovernanceToken/GovernanceTokenBase.sol:28" + }, + { + "label": "_currentSnapshotId", + "offset": 0, + "slot": "106", + "type": "t_uint256", + "contract": "Snapshottable", + "src": "contracts/extensions/Snapshottable.sol:11" + }, + { + "label": "_accountBalanceSnapshots", + "offset": 0, + "slot": "107", + "type": "t_mapping(t_address,t_struct(Snapshots)5954_storage)", + "contract": "GovernanceTokenSnapshot", + "src": "contracts/GovernanceToken/GovernanceTokenSnapshot.sol:21" + }, + { + "label": "_totalSupplySnapshots", + "offset": 0, + "slot": "108", + "type": "t_struct(Snapshots)5954_storage", + "contract": "GovernanceTokenSnapshot", + "src": "contracts/GovernanceToken/GovernanceTokenSnapshot.sol:22" + }, + { + "label": "_shareholderRegistry", + "offset": 0, + "slot": "110", + "type": "t_contract(IShareholderRegistry)7494", + "contract": "GovernanceToken", + "src": "contracts/GovernanceToken/GovernanceToken.sol:20" + }, + { + "label": "depositedTokens", + "offset": 0, + "slot": "111", + "type": "t_mapping(t_address,t_array(t_struct(DepositedTokens)5139_storage)dyn_storage)", + "contract": "GovernanceToken", + "src": "contracts/GovernanceToken/GovernanceToken.sol:33" + }, + { + "label": "settlementPeriod", + "offset": 0, + "slot": "112", + "type": "t_uint256", + "contract": "GovernanceToken", + "src": "contracts/GovernanceToken/GovernanceToken.sol:35" + } + ], + "types": { + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(DepositedTokens)5139_storage)dyn_storage": { + "label": "struct GovernanceToken.DepositedTokens[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)45_storage": { + "label": "uint256[45]", + "numberOfBytes": "1440" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_array(t_uint256)dyn_storage": { + "label": "uint256[]", + "numberOfBytes": "32" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_contract(DAORoles)7607": { + "label": "contract DAORoles", + "numberOfBytes": "20" + }, + "t_contract(INeokingdomToken)7364": { + "label": "contract INeokingdomToken", + "numberOfBytes": "20" + }, + "t_contract(IRedemptionController)7397": { + "label": "contract IRedemptionController", + "numberOfBytes": "20" + }, + "t_contract(IShareholderRegistry)7494": { + "label": "contract IShareholderRegistry", + "numberOfBytes": "20" + }, + "t_contract(IVoting)7591": { + "label": "contract IVoting", + "numberOfBytes": "20" + }, + "t_mapping(t_address,t_array(t_struct(DepositedTokens)5139_storage)dyn_storage)": { + "label": "mapping(address => struct GovernanceToken.DepositedTokens[])", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_mapping(t_address,t_uint256))": { + "label": "mapping(address => mapping(address => uint256))", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_struct(Snapshots)5954_storage)": { + "label": "mapping(address => struct GovernanceTokenSnapshot.Snapshots)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_string_storage": { + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(DepositedTokens)5139_storage": { + "label": "struct GovernanceToken.DepositedTokens", + "members": [ + { + "label": "amount", + "type": "t_uint256", + "offset": 0, + "slot": "0" + }, + { + "label": "settlementTimestamp", + "type": "t_uint256", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_struct(Snapshots)5954_storage": { + "label": "struct GovernanceTokenSnapshot.Snapshots", + "members": [ + { + "label": "ids", + "type": "t_array(t_uint256)dyn_storage", + "offset": 0, + "slot": "0" + }, + { + "label": "values", + "type": "t_array(t_uint256)dyn_storage", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + } + } } } } diff --git a/README.md b/README.md index d32fe53..0ecc7fc 100644 --- a/README.md +++ b/README.md @@ -8,30 +8,29 @@ Welcome to the Neokingdom DAO Contacts. - [NEOKingdom DAO Yellow Paper](./docs/yellowpaper/yellowpaper.md) describes why this project exists, and provides high level overview of the structure of the smart contracts. - [Flow charts](./docs/flowcharts) includes four flow charts: - - *contributor* shows how new people are added to the DAO as contributors. - - *proposal* gives an overview of the governance process of the DAO. - - *tokenomics* explains how tokens are moved from the contributor's wallet to another wallet. - - *voting* shows how contributors vote to resolutions. + - _contributor_ shows how new people are added to the DAO as contributors. + - _proposal_ gives an overview of the governance process of the DAO. + - _tokenomics_ explains how tokens are moved from the contributor's wallet to another wallet. + - _voting_ shows how contributors vote to resolutions. - [Complex flows](./docs/complex_flows): - - *voting* elaborates the logic behind the voting power distribution and delegation implemented in the Neokingdom DAO contracts - - *redemption* elaborates the logic behind the redemption process of Neokingdom DAO + - _voting_ elaborates the logic behind the voting power distribution and delegation implemented in the Neokingdom DAO contracts + - _redemption_ elaborates the logic behind the redemption process of Neokingdom DAO - Integration tests: - [Integration](./test/Integration.ts) is a collection of integration tests that touches multiple use cases. - [Integration governance+shareholders](./test/IntegrationGovernanceShareholders.ts) tests the invariant that the sum of shares and tokens is equal to the user's voting power - [Integration market+redemption](./test/IntegrationInternalMarketRedemptionController.ts) tests that users promoted from investor to contributor have the right voting power. - ## Deployments Neokingdom DAO lives on EVMOS. - [NeokingdomToken (NEOK)](https://escan.live/address/0x655ecB57432CC1370f65e5dc2309588b71b473A9) `0x655ecB57432CC1370f65e5dc2309588b71b473A9` -- [ShareholderRegistry (NEOS)](https://escan.live/address/0x4706eD7a10064801F260BBf94743f241FCEf815e) `0x4706eD7a10064801F260BBf94743f241FCEf815e` -- [GovernanceToken](https://escan.live/address/0x05d1b2355721903152768F0ec1B105Be1c35BCb4) `0x05d1b2355721903152768F0ec1B105Be1c35BCb4` -- [Voting](https://escan.live/address/0x5DC219C8CaeF7c9ECd0b97372e6Ef4fC5D827975) `0x5DC219C8CaeF7c9ECd0b97372e6Ef4fC5D827975` -- [RedemptionController](https://escan.live/address/0x7045bfaB66B55074C56aBeE34308CDa0916e086C) `0x7045bfaB66B55074C56aBeE34308CDa0916e086C` -- [InternalMarket](https://escan.live/address/0x7687155fB855e24d1416C288CbaC0AFC3B65353c) `0x7687155fB855e24d1416C288CbaC0AFC3B65353c` -- [ResolutionManager](https://escan.live/address/0xE5714C29b7acE2C6a3A80BE511ED7e5b92594204) `0xE5714C29b7acE2C6a3A80BE511ED7e5b92594204` +- [ShareholderRegistry (NEOS)](https://escan.live/address/0x4706eD7a10064801F260BBf94743f241FCEf815e) `0x4706eD7a10064801F260BBf94743f241FCEf815e`, impl `0x37aed261a1c6a3ef342ce14032636afd4a6328ca` +- [GovernanceToken](https://escan.live/address/0x05d1b2355721903152768F0ec1B105Be1c35BCb4) `0x05d1b2355721903152768F0ec1B105Be1c35BCb4`, impl `0x21bc56fa89902ad945413ed606afc1fd8c22fbe2` +- [Voting](https://escan.live/address/0x5DC219C8CaeF7c9ECd0b97372e6Ef4fC5D827975) `0x5DC219C8CaeF7c9ECd0b97372e6Ef4fC5D827975`, impl `0x3d76aaf1e34fcb191018cf8fc76dcc2547c4a59d` +- [RedemptionController](https://escan.live/address/0x7045bfaB66B55074C56aBeE34308CDa0916e086C) `0x7045bfaB66B55074C56aBeE34308CDa0916e086C`, impl `0xe961a4bb3e1289215a597cbd14df57f4cd49c091` +- [InternalMarket](https://escan.live/address/0x7687155fB855e24d1416C288CbaC0AFC3B65353c) `0x7687155fB855e24d1416C288CbaC0AFC3B65353c`, impl `0xeddf3b7810ca9dfb32e6a3e275e635987904450e` +- [ResolutionManager](https://escan.live/address/0xE5714C29b7acE2C6a3A80BE511ED7e5b92594204) `0xE5714C29b7acE2C6a3A80BE511ED7e5b92594204`, impl `0x9f589d09e7760ad46ecf9348353f348aad6b35f4` - [DAORoles](https://escan.live/address/0x6A176C92985430535E738A79749A4137BEC6C4Db) `0x6A176C92985430535E738A79749A4137BEC6C4Db` - [Operator SAFE on EVMOS](https://safe.evmos.org/evmos:0xd232121c41EF9ad4e4d0251BdCbe60b9F3D20758) `0xd232121c41EF9ad4e4d0251BdCbe60b9F3D20758` diff --git a/contracts/GovernanceToken/GovernanceToken.sol b/contracts/GovernanceToken/GovernanceToken.sol index e438e1a..e4b6055 100644 --- a/contracts/GovernanceToken/GovernanceToken.sol +++ b/contracts/GovernanceToken/GovernanceToken.sol @@ -364,7 +364,7 @@ contract GovernanceToken is Initializable, HasRole, GovernanceTokenSnapshot { DepositedTokens storage tokens = depositedTokens[from][i - 1]; if (block.timestamp >= tokens.settlementTimestamp) { if (tokens.amount > 0) { - _mint(from, tokens.amount); + ERC20Upgradeable._mint(from, tokens.amount); tokens.amount = 0; } else { break; diff --git a/contracts/InternalMarket/IDIAOracleV2.sol b/contracts/InternalMarket/IDIAOracleV2.sol new file mode 100644 index 0000000..acbfcac --- /dev/null +++ b/contracts/InternalMarket/IDIAOracleV2.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.16; + +interface IDIAOracleV2 { + function setValue( + string memory key, + uint128 value, + uint128 timestamp + ) external; + + function getValue( + string memory key + ) external view returns (uint128 value, uint128 timestamp); + + function updateOracleUpdaterAddress( + address newOracleUpdaterAddress + ) external; +} diff --git a/contracts/InternalMarket/InternalMarket.sol b/contracts/InternalMarket/InternalMarket.sol index 6ea3ca3..448faef 100644 --- a/contracts/InternalMarket/InternalMarket.sol +++ b/contracts/InternalMarket/InternalMarket.sol @@ -9,6 +9,7 @@ import "./InternalMarketBase.sol"; import { Roles } from "../extensions/Roles.sol"; import "../extensions/DAORoles.sol"; import "../extensions/HasRole.sol"; +import "./IDIAOracleV2.sol"; /** * @title InternalMarket @@ -16,16 +17,18 @@ import "../extensions/HasRole.sol"; * allowing them to make an offer, match existing offers, deposit, withdraw, and redeem locked tokens. */ contract InternalMarket is Initializable, HasRole, InternalMarketBase { + IDIAOracleV2 internal _diaPriceOracle; + /** * @dev Initializes the contract with the given roles and internal token. * @param roles DAORoles instance containing custom access control roles. - * @param governanceToken Reference to governance token. + * @param tokenInternal_ Reference to governance token. */ function initialize( DAORoles roles, - IGovernanceToken governanceToken + IGovernanceToken tokenInternal_ ) public initializer { - _initialize(governanceToken, 7 days); + _initialize(tokenInternal_, 7 days); _setRoles(roles); } @@ -90,10 +93,10 @@ contract InternalMarket is Initializable, HasRole, InternalMarketBase { * @dev Set internal token reference. * @param token The address of the internal governance token. */ - function setGovernanceToken( + function setTokenInternal( IGovernanceToken token ) public onlyRole(Roles.RESOLUTION_ROLE) zeroCheck(address(token)) { - _setGovernanceToken(token); + _setTokenInternal(token); } /** @@ -117,7 +120,7 @@ contract InternalMarket is Initializable, HasRole, InternalMarketBase { */ function setExchangePair( ERC20 token, - IStdReference oracle + IDIAOracleV2 oracle ) public onlyRole(Roles.RESOLUTION_ROLE) diff --git a/contracts/InternalMarket/InternalMarketBase.sol b/contracts/InternalMarket/InternalMarketBase.sol index 6701df0..17d2aa3 100644 --- a/contracts/InternalMarket/InternalMarketBase.sol +++ b/contracts/InternalMarket/InternalMarketBase.sol @@ -4,8 +4,7 @@ pragma solidity ^0.8.16; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "../ShareholderRegistry/IShareholderRegistry.sol"; import "../RedemptionController/IRedemptionController.sol"; -import "../PriceOracle/IStdReference.sol"; - +import "./IDIAOracleV2.sol"; import "../NeokingdomToken/INeokingdomToken.sol"; import "../GovernanceToken/IGovernanceToken.sol"; @@ -30,13 +29,13 @@ contract InternalMarketBase { mapping(uint128 => Offer) offer; } - IGovernanceToken public governanceToken; + IGovernanceToken public tokenInternal; // Cannot use IERC20 here because it lacks `decimals` ERC20 public exchangeToken; IRedemptionController public redemptionController; - IStdReference public priceOracle; + IDIAOracleV2 public priceOracle; IShareholderRegistry internal _shareholderRegistry; address public reserve; @@ -50,7 +49,7 @@ contract InternalMarketBase { IGovernanceToken _governanceToken, uint256 _offerDuration ) internal virtual { - governanceToken = _governanceToken; + tokenInternal = _governanceToken; offerDuration = _offerDuration; } @@ -62,8 +61,8 @@ contract InternalMarketBase { return offers.end++; } - function _setGovernanceToken(IGovernanceToken token) internal virtual { - governanceToken = token; + function _setTokenInternal(IGovernanceToken token) internal virtual { + tokenInternal = token; } function _setShareholderRegistry( @@ -74,7 +73,7 @@ contract InternalMarketBase { function _setExchangePair( ERC20 token, - IStdReference oracle + IDIAOracleV2 oracle ) internal virtual { exchangeToken = token; priceOracle = oracle; @@ -103,7 +102,7 @@ contract InternalMarketBase { emit OfferCreated(id, from, amount, expiredAt); require( - governanceToken.transferFrom(from, address(this), amount), + tokenInternal.transferFrom(from, address(this), amount), "InternalMarketBase: transfer failed" ); redemptionController.afterOffer(from, amount); @@ -179,7 +178,7 @@ contract InternalMarketBase { ) internal virtual { _beforeMatchOffer(from, to, amount); require( - governanceToken.transfer(to, amount), + tokenInternal.transfer(to, amount), "InternalMarketBase: transfer failed" ); require( @@ -200,9 +199,9 @@ contract InternalMarketBase { ) ) { _beforeWithdraw(from, amount); - governanceToken.unwrap(address(this), to, amount); + tokenInternal.unwrap(address(this), to, amount); } else { - governanceToken.unwrap(from, to, amount); + tokenInternal.unwrap(from, to, amount); } } @@ -214,15 +213,15 @@ contract InternalMarketBase { ) ); _beforeWithdraw(from, amount); - governanceToken.burn(address(this), amount); + tokenInternal.burn(address(this), amount); } function _deposit(address to, uint256 amount) internal virtual { - governanceToken.wrap(to, amount); + tokenInternal.wrap(to, amount); } function _finalizeDeposit(address to) internal virtual { - governanceToken.settleTokens(to); + tokenInternal.settleTokens(to); } function _redeem(address from, uint256 amount) internal virtual { @@ -231,7 +230,7 @@ contract InternalMarketBase { uint256 difference = amount - withdrawableBalance; // governanceToken is an address set by the operators of the DAO, hence trustworthy // slither-disable-start reentrancy-no-eth - governanceToken.burn(from, difference); + tokenInternal.burn(from, difference); _burn(from, withdrawableBalance); // slither-disable-end reentrancy-no-eth } else { @@ -247,9 +246,11 @@ contract InternalMarketBase { redemptionController.afterRedeem(from, amount); } - function _convertToUSDC(uint256 eurAmount) internal view returns (uint256) { - uint256 eurUsd = priceOracle.getReferenceData("EUR", "USD").rate; - uint256 usdUsdc = priceOracle.getReferenceData("USDC", "USD").rate; + function _convertToUSDC( + uint256 eurAmount + ) internal view virtual returns (uint256) { + (uint256 eurUsd, ) = priceOracle.getValue("EUR/USD"); + (uint256 usdUsdc, ) = priceOracle.getValue("USDC/USD"); // 18 is the default amount of decimals for ERC20 tokens, including neokingdom ones return diff --git a/contracts/PriceOracle/IStdReference.sol b/contracts/PriceOracle/IStdReference.sol deleted file mode 100644 index aad6a6c..0000000 --- a/contracts/PriceOracle/IStdReference.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.16; - -interface IStdReference { - /// A structure returned whenever someone requests for standard reference data. - struct ReferenceData { - uint256 rate; // base/quote exchange rate, multiplied by 1e18. - uint256 lastUpdatedBase; // UNIX epoch of the last time when base price gets updated. - uint256 lastUpdatedQuote; // UNIX epoch of the last time when quote price gets updated. - } - - /// Returns the price data for the given base/quote pair. Revert if not available. - function getReferenceData( - string memory _base, - string memory _quote - ) external view returns (ReferenceData memory); - - /// Similar to getReferenceData, but with multiple base/quote pairs at once. - function getReferenceDataBulk( - string[] memory _bases, - string[] memory _quotes - ) external view returns (ReferenceData[] memory); -} diff --git a/contracts/PriceOracle/PriceOracle.sol b/contracts/PriceOracle/PriceOracle.sol deleted file mode 100644 index 3d45253..0000000 --- a/contracts/PriceOracle/PriceOracle.sol +++ /dev/null @@ -1,72 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.16; - -import "./IStdReference.sol"; -import "@openzeppelin/contracts/access/AccessControl.sol"; - -contract PriceOracle is IStdReference, AccessControl { - event RefDataUpdate(string symbol, uint64 rate, uint64 resolveTime); - - struct RefData { - uint64 rate; // USD-rate, multiplied by 1e18. - uint64 resolveTime; // UNIX epoch when data is last resolved. - } - - mapping(string => RefData) public refs; // Mapping from symbol to ref data. - bytes32 public constant RELAYER_ROLE = keccak256("RELAYER_ROLE"); - - constructor() { - _setupRole(DEFAULT_ADMIN_ROLE, msg.sender); - // TODO: leave this out - _setupRole(RELAYER_ROLE, msg.sender); - } - - function relay( - string[] memory _symbols, - uint64[] memory _rates, - uint64[] memory _resolveTimes - ) external onlyRole(RELAYER_ROLE) { - uint256 len = _symbols.length; - require(_rates.length == len, "BAD_RATES_LENGTH"); - require(_resolveTimes.length == len, "BAD_RESOLVE_TIMES_LENGTH"); - for (uint256 idx = 0; idx < len; idx++) { - refs[_symbols[idx]] = RefData({ - rate: _rates[idx], - resolveTime: _resolveTimes[idx] - }); - emit RefDataUpdate(_symbols[idx], _rates[idx], _resolveTimes[idx]); - } - } - - function getReferenceData( - string memory _base, - string memory _quote - ) public view override returns (ReferenceData memory) { - (uint256 baseRate, uint256 baseLastUpdate) = _getRefData(_base); - (uint256 quoteRate, uint256 quoteLastUpdate) = _getRefData(_quote); - return - ReferenceData({ - rate: (baseRate * 1e18) / quoteRate, - lastUpdatedBase: baseLastUpdate, - lastUpdatedQuote: quoteLastUpdate - }); - } - - function getReferenceDataBulk( - string[] memory, - string[] memory - ) public pure override returns (ReferenceData[] memory) { - revert("NOT_IMPLEMENTED"); - } - - function _getRefData( - string memory _symbol - ) internal view returns (uint256 rate, uint256 lastUpdate) { - if (keccak256(bytes(_symbol)) == keccak256(bytes("USD"))) { - return (1e18, block.timestamp); - } - RefData storage refData = refs[_symbol]; - require(refData.resolveTime > 0, "REF_DATA_NOT_AVAILABLE"); - return (uint256(refData.rate), uint256(refData.resolveTime)); - } -} diff --git a/contracts/ResolutionManager/ResolutionManagerBase.sol b/contracts/ResolutionManager/ResolutionManagerBase.sol index 323e078..2e022a8 100644 --- a/contracts/ResolutionManager/ResolutionManagerBase.sol +++ b/contracts/ResolutionManager/ResolutionManagerBase.sol @@ -212,25 +212,31 @@ abstract contract ResolutionManagerBase { // power. Hence we are forcing the the contributor to have no delegation for this // resolution so to have the voting power "clean". Delegation is restored // after the snapshot. - address delegated; - if (resolution.addressedContributor != address(0)) { - delegated = _voting.getDelegate(resolution.addressedContributor); - if (delegated != resolution.addressedContributor) { - _voting.delegateFrom( - resolution.addressedContributor, - resolution.addressedContributor - ); - } + address addressedContributor = resolution.addressedContributor; + address originalDelegate; + bytes32 originalStatus; + + if (addressedContributor != address(0)) { + originalDelegate = _voting.getDelegate(addressedContributor); + originalStatus = _shareholderRegistry.getStatus( + addressedContributor + ); + // Downgrading to investor removes delegation + _shareholderRegistry.setStatus( + _shareholderRegistry.INVESTOR_STATUS(), + addressedContributor + ); } resolution.snapshotId = _snapshotAll(); - if (resolution.addressedContributor != address(0)) { - if (delegated != resolution.addressedContributor) { - _voting.delegateFrom( - resolution.addressedContributor, - delegated - ); + if (addressedContributor != address(0)) { + _shareholderRegistry.setStatus( + originalStatus, + addressedContributor + ); + if (addressedContributor != originalDelegate) { + _voting.delegateFrom(addressedContributor, originalDelegate); } } } @@ -362,7 +368,7 @@ abstract contract ResolutionManagerBase { resolution.snapshotId ); - // If sender has a delegate load voting power from GovernanceToken + // If sender has a delegate, load voting power from GovernanceToken if (delegate != msg.sender) { votingPower = _governanceToken.balanceOfAt( @@ -492,18 +498,6 @@ abstract contract ResolutionManagerBase { resolution.snapshotId ); - if (resolution.addressedContributor != address(0)) { - totalVotingPower -= - _governanceToken.balanceOfAt( - resolution.addressedContributor, - resolution.snapshotId - ) + - _shareholderRegistry.balanceOfAt( - resolution.addressedContributor, - resolution.snapshotId - ); - } - bool hasQuorum = resolution.yesVotesTotal * 100 >= resolutionType.quorum * totalVotingPower; diff --git a/contracts/ShareholderRegistry/IShareholderRegistry.sol b/contracts/ShareholderRegistry/IShareholderRegistry.sol index 224db9e..9a93447 100644 --- a/contracts/ShareholderRegistry/IShareholderRegistry.sol +++ b/contracts/ShareholderRegistry/IShareholderRegistry.sol @@ -12,6 +12,8 @@ interface IShareholderRegistry is ISnapshot { function MANAGING_BOARD_STATUS() external view returns (bytes32); + function setStatus(bytes32 status, address account) external; + function getStatus(address account) external view returns (bytes32); function getStatusAt( diff --git a/contracts/mocks/DIAOracleV2Mock.sol b/contracts/mocks/DIAOracleV2Mock.sol new file mode 100644 index 0000000..81c4a76 --- /dev/null +++ b/contracts/mocks/DIAOracleV2Mock.sol @@ -0,0 +1,49 @@ +/** + *Submitted for verification at escan.live on 2023-06-20 + */ + +// compiled using solidity 0.7.4 + +pragma solidity ^0.8.16; + +contract DIAOracleV2Mock { + mapping(string => uint256) public values; + address oracleUpdater; + + event OracleUpdate(string key, uint128 value, uint128 timestamp); + event UpdaterAddressChange(address newUpdater); + + constructor() { + oracleUpdater = msg.sender; + setValue("USDC/USD", 100056862, 1688997110); + setValue("EUR/USD", 109479913, 1688997110); + } + + function setValue( + string memory key, + uint128 value, + uint128 timestamp + ) public { + require(msg.sender == oracleUpdater); + uint256 cValue = (((uint256)(value)) << 128) + timestamp; + values[key] = cValue; + emit OracleUpdate(key, value, timestamp); + } + + function getValue( + string memory key + ) external view returns (uint128, uint128) { + uint256 cValue = values[key]; + uint128 timestamp = (uint128)(cValue % 2 ** 128); + uint128 value = (uint128)(cValue >> 128); + return (value, timestamp); + } + + function updateOracleUpdaterAddress( + address newOracleUpdaterAddress + ) public { + require(msg.sender == oracleUpdater); + oracleUpdater = newOracleUpdaterAddress; + emit UpdaterAddressChange(newOracleUpdaterAddress); + } +} diff --git a/contracts/mocks/ShareholderRegistryMock.sol b/contracts/mocks/ShareholderRegistryMock.sol index 171a01b..17c1609 100644 --- a/contracts/mocks/ShareholderRegistryMock.sol +++ b/contracts/mocks/ShareholderRegistryMock.sol @@ -40,6 +40,9 @@ contract ShareholderRegistryMock is Initializable, IShareholderRegistry { return mockResult_isAtLeast[status][account]; } + // Unneeded for testing + function setStatus(bytes32 status, address account) public {} + // Unneeded for testing function getStatus( address account diff --git a/hardhat.config.ts b/hardhat.config.ts index 15c2ab2..88acca2 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -77,7 +77,7 @@ const config: HardhatUserConfig = { accounts: [TEVMOS_PRIVATE_KEY], }, evmos: { - url: "https://jsonrpc-evmos-ia.cosmosia.notional.ventures/", + url: "https://eth.bd.evmos.org:8545", accounts: [EVMOS_PRIVATE_KEY], }, }, diff --git a/lib/config.ts b/lib/config.ts index e63a11e..b97767c 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -3,8 +3,8 @@ import { readFile } from "fs/promises"; import { HardhatRuntimeEnvironment } from "hardhat/types"; import { + DIAOracleV2Mock__factory, GovernanceToken__factory, - PriceOracle__factory, ProxyAdmin__factory, ResolutionManager__factory, ShareholderRegistry__factory, @@ -54,8 +54,8 @@ type ContractFactory = | typeof GovernanceToken__factory | typeof Voting__factory | typeof TokenMock__factory - | typeof PriceOracle__factory - | typeof ProxyAdmin__factory; + | typeof ProxyAdmin__factory + | typeof DIAOracleV2Mock__factory; export async function loadContract( hre: HardhatRuntimeEnvironment, @@ -70,6 +70,7 @@ export async function loadContract( const [deployer] = await hre.ethers.getSigners(); const { chainId, name: networkName } = await hre.ethers.provider.getNetwork(); const addresses = networks[chainId]; + console.log(networks); if (!addresses || !addresses[name]) { console.error(`Cannot find address for ${name} in network ${networkName}.`); diff --git a/lib/environment/memory.ts b/lib/environment/memory.ts index ddff8fc..8374526 100644 --- a/lib/environment/memory.ts +++ b/lib/environment/memory.ts @@ -3,10 +3,10 @@ import { ethers, upgrades } from "hardhat"; import { DAORoles, + DIAOracleV2Mock, GovernanceToken, InternalMarket, NeokingdomToken, - PriceOracle, ProxyAdmin, RedemptionController, ResolutionManager, @@ -79,9 +79,6 @@ export class NeokingdomDAOMemory extends NeokingdomDAO { case "NeokingdomToken": this.contracts.neokingdomToken = contract as NeokingdomToken; break; - case "PriceOracle": - this.contracts.priceOracle = contract as PriceOracle; - break; case "RedemptionController": this.contracts.redemptionController = contract as RedemptionController; break; @@ -99,6 +96,9 @@ export class NeokingdomDAOMemory extends NeokingdomDAO { break; case "ProxyAdmin": this.contracts.proxyAdmin = contract as ProxyAdmin; + break; + case "DIAOracleV2Mock": + this.contracts.diaOracleV2Mock = contract as DIAOracleV2Mock; } } } diff --git a/lib/internal/types.ts b/lib/internal/types.ts index d27e2ba..7aec239 100644 --- a/lib/internal/types.ts +++ b/lib/internal/types.ts @@ -6,14 +6,14 @@ import { HardhatRuntimeEnvironment } from "hardhat/types"; import { DAORoles, DAORoles__factory, + DIAOracleV2Mock, + DIAOracleV2Mock__factory, GovernanceToken, GovernanceToken__factory, InternalMarket, InternalMarket__factory, NeokingdomToken, NeokingdomToken__factory, - PriceOracle, - PriceOracle__factory, ProxyAdmin, ProxyAdmin__factory, RedemptionController, @@ -34,13 +34,13 @@ export const FACTORIES = { InternalMarket: InternalMarket__factory, GovernanceToken: GovernanceToken__factory, NeokingdomToken: NeokingdomToken__factory, - PriceOracle: PriceOracle__factory, RedemptionController: RedemptionController__factory, ResolutionManager: ResolutionManager__factory, ShareholderRegistry: ShareholderRegistry__factory, TokenMock: TokenMock__factory, Voting: Voting__factory, ProxyAdmin: ProxyAdmin__factory, + DIAOracleV2Mock: DIAOracleV2Mock__factory, } as const; export type ContractNames = keyof typeof FACTORIES; @@ -61,13 +61,13 @@ export type NeokingdomContracts = { internalMarket: InternalMarket; governanceToken: GovernanceToken; neokingdomToken: NeokingdomToken; - priceOracle: PriceOracle; redemptionController: RedemptionController; resolutionManager: ResolutionManager; shareholderRegistry: ShareholderRegistry; tokenMock: TokenMock; voting: Voting; proxyAdmin: ProxyAdmin; + diaOracleV2Mock: DIAOracleV2Mock; }; export type Context = {}; @@ -94,13 +94,13 @@ export const CONTRACT_NAMES = [ "internalMarket", "governanceToken", "neokingdomToken", - "priceOracle", "redemptionController", "resolutionManager", "shareholderRegistry", "tokenMock", "voting", "proxyAdmin", + "diaOracleV2Mock", ]; export function isNeokingdomContracts( diff --git a/lib/sequence/deploy.ts b/lib/sequence/deploy.ts index 9af4135..26de7f2 100644 --- a/lib/sequence/deploy.ts +++ b/lib/sequence/deploy.ts @@ -42,7 +42,7 @@ export const DEPLOY_SEQUENCE: Sequence = [ ///////////////////// (c) => c.deploy("DAORoles"), (c) => c.deploy("TokenMock"), - (c) => c.deploy("PriceOracle"), + (c) => c.deploy("DIAOracleV2Mock"), (c) => c.deployProxy("Voting", [c.daoRoles.address]), (c) => c.deployProxy("GovernanceToken", [ @@ -71,8 +71,6 @@ export const DEPLOY_SEQUENCE: Sequence = [ c.voting.address, ]), (c) => c.deploy("ProxyAdmin"), - (c) => c.priceOracle.relay(["EUR", "USD"], [1, 1], [1, 1]), - (c) => c.priceOracle.relay(["USDC", "USD"], [1, 1], [1, 1]), // Set ACLs ///////////// @@ -123,13 +121,13 @@ export const DEPLOY_SEQUENCE: Sequence = [ (c) => c.internalMarket.setRedemptionController(c.redemptionController.address), + (c) => c.internalMarket.setReserve(c.reserve), + (c) => c.internalMarket.setShareholderRegistry(c.shareholderRegistry.address), + (c) => c.diaOracleV2Mock.setValue("EUR/USD", 100000000, 1688997107), + (c) => c.diaOracleV2Mock.setValue("USDC/USD", 100000000, 1688997107), (c) => c.internalMarket.setExchangePair( c.tokenMock.address, - c.priceOracle.address - //"0x15c3eb3b621d1bff62cba1c9536b7c1ae9149b57", - //"0x666CDb721838B1b8C0C234DAa0D9Dbc821103aA5" + c.diaOracleV2Mock.address ), - (c) => c.internalMarket.setReserve(c.reserve), - (c) => c.internalMarket.setShareholderRegistry(c.shareholderRegistry.address), ]; diff --git a/lib/sequence/setup.ts b/lib/sequence/setup.ts index 1fe669b..8ce4899 100644 --- a/lib/sequence/setup.ts +++ b/lib/sequence/setup.ts @@ -5,6 +5,12 @@ import { expandable } from "../internal/core"; import { Sequence, SetupContext } from "../internal/types"; export const SETUP_SEQUENCE: Sequence = [ + (c) => + c.internalMarket.setExchangePair( + "0x15c3eb3b621d1bff62cba1c9536b7c1ae9149b57", // USDC + "0x3141274e597116f0bfcf07aeafa81b6b39c94325" // DIA Price Oracle + ), + // Give each address one share expandable((preprocessContext: SetupContext) => preprocessContext.contributors.map( @@ -61,6 +67,11 @@ export const SETUP_SEQUENCE_TESTNET: Sequence = [ 60 * 3, false ), + (c) => + c.internalMarket.setExchangePair( + c.tokenMock.address, + c.diaOracleV2Mock.address + ), expandable((preprocessContext: SetupContext) => preprocessContext.contributors.map( (contributor) => (c) => diff --git a/lib/utils.ts b/lib/utils.ts index bd925d8..f9dd898 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -7,10 +7,10 @@ import * as readline from "readline"; import { DAORoles, + DIAOracleV2Mock, GovernanceToken, InternalMarket, NeokingdomToken, - PriceOracle, ProxyAdmin, RedemptionController, ResolutionManager, @@ -204,7 +204,6 @@ export async function loadContracts( internalMarket: await _loadContract("InternalMarket"), governanceToken: await _loadContract("GovernanceToken"), neokingdomToken: await _loadContract("NeokingdomToken"), - priceOracle: await _loadContract("PriceOracle"), redemptionController: await _loadContract( "RedemptionController" ), @@ -217,6 +216,7 @@ export async function loadContracts( tokenMock: await _loadContract("TokenMock"), voting: await _loadContract("Voting"), proxyAdmin: await _loadContract("ProxyAdmin"), + diaOracleV2Mock: await _loadContract("DIAOracleV2Mock"), }; } diff --git a/tasks/admin.ts b/tasks/admin.ts index e2019b6..084359a 100644 --- a/tasks/admin.ts +++ b/tasks/admin.ts @@ -13,3 +13,18 @@ task("admin:transfer", "Transfer ProxyAdmin ownership") console.log("Done"); }); + +task("admin:exchange:set", "Set market exchange pair") + .addParam("oracle", "Oracle Address") + .addParam("usdc", "USDC Address") + .setAction( + async ({ oracle, usdc }: { oracle: string; usdc: string }, hre) => { + const neokingdom = await NeokingdomDAOHardhat.initialize(hre); + const contracts = await neokingdom.loadContracts(); + + const tx = await contracts.internalMarket.setExchangePair(usdc, oracle); + await tx.wait(1); + + console.log("Done"); + } + ); diff --git a/tasks/index.ts b/tasks/index.ts index 12b83e5..38adcaa 100644 --- a/tasks/index.ts +++ b/tasks/index.ts @@ -1,7 +1,6 @@ import "./admin"; import "./delegate"; import "./deploy"; -import "./oracle"; import "./resolution"; import "./status"; import "./tokens"; diff --git a/tasks/oracle.ts b/tasks/oracle.ts deleted file mode 100644 index cf5ee37..0000000 --- a/tasks/oracle.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { task } from "hardhat/config"; - -import { PriceOracle__factory } from "../typechain"; - -import { loadContract } from "../lib/config"; - -task("ref", "Get reference data") - .addPositionalParam("base", "Base symbol") - .addPositionalParam("quote", "Quote symbol") - .setAction(async ({ base, quote }: { base: string; quote: string }, hre) => { - const contract = await loadContract( - hre, - PriceOracle__factory, - "PriceOracle" - ); - - const result = await contract.getReferenceData(base, quote); - console.log(result); - }); - -task("add-relayer", "Add relayer") - .addPositionalParam("account", "Relayer address") - .setAction(async ({ account }: { account: string }, hre) => { - const contract = await loadContract( - hre, - PriceOracle__factory, - "PriceOracle" - ); - - const tx = await contract.grantRole(await contract.RELAYER_ROLE(), account); - await tx.wait(1); - console.log("Done"); - }); - -task("relay", "Add reference data") - .addParam("symbol", "Symbol") - .addParam("rate", "Rate") - .addParam("time", "Resolve time") - .setAction( - async ( - { symbol, rate, time }: { symbol: string; rate: number; time: number }, - hre - ) => { - const contract = await loadContract( - hre, - PriceOracle__factory, - "PriceOracle" - ); - - console.log("Relyaing"); - console.log(` Symbols ${symbol}`); - console.log(` Rates ${rate}`); - console.log(` Times ${time}`); - - const tx = await contract.relay([symbol], [rate], [time]); - await tx.wait(1); - console.log("Done"); - } - ); diff --git a/tasks/upgrade.ts b/tasks/upgrade.ts index 013de47..ca0f49d 100644 --- a/tasks/upgrade.ts +++ b/tasks/upgrade.ts @@ -1,6 +1,7 @@ import { task } from "hardhat/config"; import { + GovernanceToken, GovernanceToken__factory, InternalMarket__factory, ProxyAdmin, @@ -38,17 +39,23 @@ task("upgrade:market", "Upgrade Internal Market", async (_, hre) => { const neokingdom = await NeokingdomDAOHardhat.initialize(hre); const contracts = await neokingdom.loadContracts(); - console.log("Upgrade InternalMarket"); + console.log(`Upgrade InternalMarket ${contracts.internalMarket.address}`); console.log(" Network:", hre.network.name); - const internalMarketContract = await hre.upgrades.upgradeProxy( - contracts.internalMarket.address, - internalMarketFactory + const answer = await question( + "This action is irreversible. Please type 'GO' to continue.\n" ); - await internalMarketContract.deployed(); - console.log(" Address:", internalMarketContract.address); - console.log("InternalMarket upgraded"); + if (answer == "GO") { + const internalMarketContract = await hre.upgrades.upgradeProxy( + contracts.internalMarket.address, + internalMarketFactory + ); + await internalMarketContract.deployed(); + + console.log(" Address:", internalMarketContract.address); + console.log("InternalMarket upgraded"); + } }); task("upgrade:governance", "Upgrade Governance Token", async (_, hre) => { @@ -58,7 +65,7 @@ task("upgrade:governance", "Upgrade Governance Token", async (_, hre) => { const neokingdom = await NeokingdomDAOHardhat.initialize(hre); const contracts = await neokingdom.loadContracts(); - console.log("Upgrade GovernanceToken"); + console.log(`Upgrade GovernanceToken ${contracts.governanceToken.address}`); console.log(" Network:", hre.network.name); const answer = await question( @@ -66,10 +73,10 @@ task("upgrade:governance", "Upgrade Governance Token", async (_, hre) => { ); if (answer == "GO") { - const governanceTokenContract = await hre.upgrades.upgradeProxy( + const governanceTokenContract = (await hre.upgrades.upgradeProxy( contracts.governanceToken.address, governanceTokenFactory - ); + )) as GovernanceToken; await governanceTokenContract.deployed(); console.log(" Address:", governanceTokenContract.address); @@ -88,6 +95,8 @@ task("impl", "Get Proxy Impl") deployer ) as ProxyAdmin; + console.log(" Proxy Owner:", await proxyAdmin.owner()); + console.log( " Address:", await proxyAdmin.getProxyImplementation(address) diff --git a/test/GovernanceToken.ts b/test/GovernanceToken.ts index e36e07b..b62e865 100644 --- a/test/GovernanceToken.ts +++ b/test/GovernanceToken.ts @@ -262,7 +262,7 @@ describe("GovernanceToken", () => { "GovernanceToken: transfer failed" ); }); - + it("should fail wrapping 0 tokens", async () => { await expect( governanceToken.connect(contributor).wrap(contributor.address, 0) @@ -400,7 +400,7 @@ describe("GovernanceToken", () => { expect(result).equal(41); }); - it("should only not mint non cooled tokens", async () => { + it("should not mint non cooled tokens", async () => { await governanceToken.wrap(contributor.address, 42); await governanceToken.settleTokens(contributor.address); @@ -436,6 +436,15 @@ describe("GovernanceToken", () => { expect(balanceAfter).equal(balanceBefore.add(42)); }); + it("should not mint an equivalent amount of neok tokens to the governance contract", async () => { + neokingdomToken.mint.reset(); + await governanceToken.wrap(contributor.address, 42); + await timeTravel(7); + await governanceToken.settleTokens(contributor.address); + + expect(neokingdomToken.mint).to.not.have.been.called; + }); + it("should not call RedemptionController.afterMint", async () => { await governanceToken.wrap(contributor.address, 42); await timeTravel(7); diff --git a/test/Integration.ts b/test/Integration.ts index c36708d..2960394 100644 --- a/test/Integration.ts +++ b/test/Integration.ts @@ -94,7 +94,6 @@ describe("Integration", async () => { governanceToken, neokingdomToken, shareholderRegistry, - resolutionManager, internalMarket, redemptionController, @@ -1332,6 +1331,13 @@ describe("Integration", async () => { }); it("back and forth NEOK <-> Governance", async () => { + async function _expectWrapped(count: number) { + let wrappedNEOKs = await neokingdomToken.balanceOf( + governanceToken.address + ); + expect(wrappedNEOKs).equal(count); + } + await governanceToken.setSettlementPeriod(3600 * 24 * 7); const share = parseEther("1"); await shareholderRegistry.mint(user1.address, parseEther("1")); @@ -1339,18 +1345,25 @@ describe("Integration", async () => { await shareholderRegistry.setStatus(contributorStatus, user1.address); await shareholderRegistry.setStatus(contributorStatus, user2.address); + await _expectWrapped(0); + // 15 Governance Tokens to user2 await governanceToken.mint(user2.address, 15); + await _expectWrapped(15); + // 5 Governance tokens minted to user1 await governanceToken.mint(user1.address, 5); + await _expectWrapped(20); // user2 withdraws 10 Governance tokens to user1 await internalMarket.connect(user2).makeOffer(10); await timeTravel(7, true); await internalMarket.connect(user2).withdraw(user1.address, 10); + await _expectWrapped(10); // user1 deposit 4 NEOK await internalMarket.connect(user1).deposit(4); + await _expectWrapped(14); // user1 voting power is 5 expect(await voting.getVotingPower(user1.address)).equal(share.add(5)); // user1 offers 3 NEOK @@ -1365,6 +1378,7 @@ describe("Integration", async () => { ); // user1 deposit 3 NEOK await internalMarket.connect(user1).deposit(3); + await _expectWrapped(17); // user1 voting power is 2 expect(await voting.getVotingPower(user1.address)).equal(share.add(2)); // deposit is finalized @@ -1377,6 +1391,8 @@ describe("Integration", async () => { await governanceToken.settleTokens(user1.address); // user1 voting power is 9 expect(await voting.getVotingPower(user1.address)).equal(share.add(9)); + + await _expectWrapped(17); }); it("internal and external token amounts", async () => { @@ -1537,6 +1553,47 @@ describe("Integration", async () => { }); }); + it("total voting power for a resolution with exclusion doesn't include the voting power of the excluded contributor", async () => { + await _makeContributor(user1, 20); + await _makeContributor(user2, 70); + await _makeContributor(user3, 10); + + // We have an extra of 4 shares: + // 3 are the shares of user1, user2, and user3 + // 1 is the share of the board + expect(await voting.getTotalVotingPower()).equal(e(20 + 70 + 10 + 4)); + + // resolution 1 excludes user 2 + const abi = ["function setStatus(bytes32 status, address account)"]; + const iface = new ethers.utils.Interface(abi); + const data = iface.encodeFunctionData("setStatus", [ + investorStatus, + user2.address, + ]); + + // Contributors propose a distrust vote against user3 + const distrust = ++currentResolution; + await resolutionManager + .connect(user1) + .createResolutionWithExclusion( + "Qxdistrust", + 0, + [shareholderRegistry.address], + [data], + user2.address + ); + + await resolutionManager + .connect(managingBoard) + .approveResolution(distrust); + const { snapshotId } = await resolutionManager.resolutions(distrust); + + // Now we have 3 extra shares as user2 is not a contributor anymore + expect(await voting.getTotalVotingPowerAt(snapshotId)).equal( + e(20 + 10 + 3) + ); + }); + it("voting with exclusion stress test", async () => { await _makeContributor(user1, 20); await _makeContributor(user2, 70); diff --git a/test/InternalMarket.ts b/test/InternalMarket.ts index 75956ad..a22626e 100644 --- a/test/InternalMarket.ts +++ b/test/InternalMarket.ts @@ -12,12 +12,11 @@ import { ERC20, IGovernanceToken, IRedemptionController, - IStdReference, InternalMarket, InternalMarket__factory, ShareholderRegistry, } from "../typechain"; -import { governanceToken } from "../typechain/contracts"; +import { IDIAOracleV2 } from "../typechain/contracts/InternalMarket/IDIAOracleV2"; import { getEVMTimestamp, mineEVMBlock, setEVMTimestamp } from "./utils/evm"; import { roles } from "./utils/roles"; @@ -39,7 +38,7 @@ describe("InternalMarket", async () => { let registry: FakeContract; let internalMarket: InternalMarket; let redemption: FakeContract; - let stdReference: FakeContract; + let oracle: FakeContract; let usdc: FakeContract; let deployer: SignerWithAddress; let alice: SignerWithAddress; @@ -70,7 +69,7 @@ describe("InternalMarket", async () => { ])) as InternalMarket; redemption = await smock.fake("IRedemptionController"); - stdReference = await smock.fake("IStdReference"); + oracle = await smock.fake("IDIAOracleV2"); registry = await smock.fake("ShareholderRegistry"); RESOLUTION_ROLE = await roles.RESOLUTION_ROLE(); @@ -79,7 +78,7 @@ describe("InternalMarket", async () => { .whenCalledWith(RESOLUTION_ROLE, deployer.address) .returns(true); await internalMarket.setRedemptionController(redemption.address); - await internalMarket.setExchangePair(usdc.address, stdReference.address); + await internalMarket.setExchangePair(usdc.address, oracle.address); await internalMarket.setReserve(reserve.address); await internalMarket.setShareholderRegistry(registry.address); @@ -93,17 +92,16 @@ describe("InternalMarket", async () => { governanceToken.unwrap.reset(); usdc.transfer.reset(); usdc.transferFrom.reset(); - stdReference.getReferenceData.reset(); + oracle.getValue.reset(); registry.isAtLeast.returns(true); // make transferFrom always succeed governanceToken.transferFrom.returns(true); // Exchange rate is always 1 - stdReference.getReferenceData.returns({ - rate: parseEther("1"), - lastUpdatedBase: parseEther("0"), - lastUpdatedQuote: parseEther("0"), + oracle.getValue.returns({ + value: parseEther("1"), + timestamp: parseEther("0"), }); }); @@ -137,20 +135,20 @@ describe("InternalMarket", async () => { }); }); - describe("setGovernanceToken", async () => { + describe("setTokenInternal", async () => { it("should allow a resolution to set token and oracle addresses", async () => { // Alice is not a token, but it's a valid address, so we use it to test this function daoRoles.hasRole .whenCalledWith(RESOLUTION_ROLE, deployer.address) .returns(true); - await internalMarket.setGovernanceToken(alice.address); - expect(await internalMarket.governanceToken()).equal(alice.address); + await internalMarket.setTokenInternal(alice.address); + expect(await internalMarket.tokenInternal()).equal(alice.address); }); it("should revert if anyone else tries to set the token address", async () => { // Alice is not a token, but it's a valid address, so we use it to test this function await expect( - internalMarket.connect(alice).setGovernanceToken(alice.address) + internalMarket.connect(alice).setTokenInternal(alice.address) ).revertedWith( `AccessControl: account ${alice.address.toLowerCase()} is missing role ${RESOLUTION_ROLE}` ); @@ -221,18 +219,14 @@ describe("InternalMarket", async () => { describe("when the exchange rate is 1/1", async () => { beforeEach(async () => { - stdReference.getReferenceData.whenCalledWith("EUR", "USD").returns({ - rate: parseEther("1"), - lastUpdatedBase: parseEther("0"), - lastUpdatedQuote: parseEther("0"), + oracle.getValue.whenCalledWith("EUR/USD").returns({ + value: parseEther("1"), + timestamp: parseEther("0"), + }); + oracle.getValue.whenCalledWith("USDC/USD").returns({ + value: parseEther("1"), + timestamp: parseEther("0"), }); - stdReference.getReferenceData - .whenCalledWith("USDC", "USD") - .returns({ - rate: parseEther("1"), - lastUpdatedBase: parseEther("0"), - lastUpdatedQuote: parseEther("0"), - }); }); it("should burn the 10 DAO tokens for 10 USDC of the reserve", async () => { @@ -251,18 +245,14 @@ describe("InternalMarket", async () => { describe("when the exchange rate is 1/2", async () => { beforeEach(async () => { - stdReference.getReferenceData.whenCalledWith("EUR", "USD").returns({ - rate: parseEther("2"), - lastUpdatedBase: parseEther("0"), - lastUpdatedQuote: parseEther("0"), + oracle.getValue.whenCalledWith("EUR/USD").returns({ + value: parseEther("2"), + timestamp: parseEther("0"), + }); + oracle.getValue.whenCalledWith("USDC/USD").returns({ + value: parseEther("1"), + timestamp: parseEther("0"), }); - stdReference.getReferenceData - .whenCalledWith("USDC", "USD") - .returns({ - rate: parseEther("1"), - lastUpdatedBase: parseEther("0"), - lastUpdatedQuote: parseEther("0"), - }); }); it("should burn 10 DAO token for 20 USDC", async () => { @@ -282,18 +272,14 @@ describe("InternalMarket", async () => { describe("when the exchange rate is 1.12 eur/usd and 0.998 usdc/usd", async () => { beforeEach(async () => { - stdReference.getReferenceData.whenCalledWith("EUR", "USD").returns({ - rate: parseEther("1.12"), - lastUpdatedBase: parseEther("0"), - lastUpdatedQuote: parseEther("0"), + oracle.getValue.whenCalledWith("EUR/USD").returns({ + value: parseEther("1.12"), + timestamp: parseEther("0"), + }); + oracle.getValue.whenCalledWith("USDC/USD").returns({ + value: parseEther("0.998"), + timestamp: parseEther("0"), }); - stdReference.getReferenceData - .whenCalledWith("USDC", "USD") - .returns({ - rate: parseEther("0.998"), - lastUpdatedBase: parseEther("0"), - lastUpdatedQuote: parseEther("0"), - }); }); it("should burn the 10 DAO tokens for 11.222444 USDC", async () => { @@ -312,18 +298,14 @@ describe("InternalMarket", async () => { describe("when the exchange rate is 2/1", async () => { beforeEach(async () => { - stdReference.getReferenceData.whenCalledWith("EUR", "USD").returns({ - rate: parseEther("1"), - lastUpdatedBase: parseEther("0"), - lastUpdatedQuote: parseEther("0"), + oracle.getValue.whenCalledWith("EUR/USD").returns({ + value: parseEther("1"), + timestamp: parseEther("0"), + }); + oracle.getValue.whenCalledWith("USDC/USD").returns({ + value: parseEther("2"), + timestamp: parseEther("0"), }); - stdReference.getReferenceData - .whenCalledWith("USDC", "USD") - .returns({ - rate: parseEther("2"), - lastUpdatedBase: parseEther("0"), - lastUpdatedQuote: parseEther("0"), - }); }); it("should burn the 11 DAO tokens for 5.5 USDC", async () => { @@ -576,15 +558,13 @@ describe("InternalMarket", async () => { describe("when the exchange rate is 1/1", async () => { beforeEach(async () => { - stdReference.getReferenceData.whenCalledWith("EUR", "USD").returns({ - rate: parseEther("1"), - lastUpdatedBase: parseEther("0"), - lastUpdatedQuote: parseEther("0"), + oracle.getValue.whenCalledWith("EUR/USD").returns({ + value: parseEther("1"), + timestamp: parseEther("0"), }); - stdReference.getReferenceData.whenCalledWith("USDC", "USD").returns({ - rate: parseEther("1"), - lastUpdatedBase: parseEther("0"), - lastUpdatedQuote: parseEther("0"), + oracle.getValue.whenCalledWith("USDC/USD").returns({ + value: parseEther("1"), + timestamp: parseEther("0"), }); }); @@ -608,15 +588,13 @@ describe("InternalMarket", async () => { describe("when the exchange rate is 1/2", async () => { beforeEach(async () => { - stdReference.getReferenceData.whenCalledWith("EUR", "USD").returns({ - rate: parseEther("2"), - lastUpdatedBase: parseEther("0"), - lastUpdatedQuote: parseEther("0"), + oracle.getValue.whenCalledWith("EUR/USD").returns({ + value: parseEther("2"), + timestamp: parseEther("0"), }); - stdReference.getReferenceData.whenCalledWith("USDC", "USD").returns({ - rate: parseEther("1"), - lastUpdatedBase: parseEther("0"), - lastUpdatedQuote: parseEther("0"), + oracle.getValue.whenCalledWith("USDC/USD").returns({ + value: parseEther("1"), + timestamp: parseEther("0"), }); }); @@ -640,15 +618,13 @@ describe("InternalMarket", async () => { describe("when the exchange rate is 1.12 eur/usd and 0.998 usdc/usd", async () => { beforeEach(async () => { - stdReference.getReferenceData.whenCalledWith("EUR", "USD").returns({ - rate: parseEther("1.12"), - lastUpdatedBase: parseEther("0"), - lastUpdatedQuote: parseEther("0"), + oracle.getValue.whenCalledWith("EUR/USD").returns({ + value: parseEther("1.12"), + timestamp: parseEther("0"), }); - stdReference.getReferenceData.whenCalledWith("USDC", "USD").returns({ - rate: parseEther("0.998"), - lastUpdatedBase: parseEther("0"), - lastUpdatedQuote: parseEther("0"), + oracle.getValue.whenCalledWith("USDC/USD").returns({ + value: parseEther("0.998"), + timestamp: parseEther("0"), }); }); @@ -672,15 +648,13 @@ describe("InternalMarket", async () => { describe("when the exchange rate is 2/1", async () => { beforeEach(async () => { - stdReference.getReferenceData.whenCalledWith("EUR", "USD").returns({ - rate: parseEther("1"), - lastUpdatedBase: parseEther("0"), - lastUpdatedQuote: parseEther("0"), + oracle.getValue.whenCalledWith("EUR/USD").returns({ + value: parseEther("1"), + timestamp: parseEther("0"), }); - stdReference.getReferenceData.whenCalledWith("USDC", "USD").returns({ - rate: parseEther("2"), - lastUpdatedBase: parseEther("0"), - lastUpdatedQuote: parseEther("0"), + oracle.getValue.whenCalledWith("USDC/USD").returns({ + value: parseEther("2"), + timestamp: parseEther("0"), }); }); diff --git a/test/PriceOracle.ts b/test/PriceOracle.ts deleted file mode 100644 index 7bfd934..0000000 --- a/test/PriceOracle.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; -import chai from "chai"; -import chaiAsPromised from "chai-as-promised"; -import { solidity } from "ethereum-waffle"; -import { BigNumber } from "ethers"; -import { parseEther } from "ethers/lib/utils"; -import { ethers, network } from "hardhat"; - -import { PriceOracle, PriceOracle__factory } from "../typechain"; - -chai.use(solidity); -chai.use(chaiAsPromised); -const { expect } = chai; -let snapshotId: string; - -describe("PriceOracle", async () => { - let priceOracle: PriceOracle; - let deployer: SignerWithAddress, account: SignerWithAddress; - - before(async () => { - [deployer, account] = await ethers.getSigners(); - - const PriceOracleFactory = (await ethers.getContractFactory( - "PriceOracle", - deployer - )) as PriceOracle__factory; - - priceOracle = await PriceOracleFactory.deploy(); - await priceOracle.deployed(); - }); - - beforeEach(async () => { - snapshotId = await network.provider.send("evm_snapshot"); - }); - - afterEach(async () => { - await network.provider.send("evm_revert", [snapshotId]); - }); - - describe("relay", async () => { - it("should fail if not called by a relayer", async () => { - await expect( - priceOracle.connect(account).relay(["test"], [42], [43]) - ).revertedWith( - `AccessControl: account ${account.address.toLowerCase()} is missing role ${await priceOracle.RELAYER_ROLE()}` - ); - }); - - it("should fail if rates length doesn't match symbol length", async () => { - await expect(priceOracle.relay(["test"], [42, 43], [43])).revertedWith( - "BAD_RATES_LENGTH" - ); - }); - - it("should fail if resolve times length doesn't match symbol length", async () => { - await expect(priceOracle.relay(["test"], [42], [43, 42])).revertedWith( - "BAD_RESOLVE_TIMES_LENGTH" - ); - }); - - it("should emit 1 event per element", async () => { - await expect(priceOracle.relay(["test1", "test2"], [42, 43], [44, 45])) - .to.emit(priceOracle, "RefDataUpdate") - .withArgs("test1", 42, 44) - .to.emit(priceOracle, "RefDataUpdate") - .withArgs("test2", 43, 45); - }); - }); - - describe("getReferenceDataBulk", async () => { - it("should fail", async () => { - await expect(priceOracle.getReferenceDataBulk([], [])).revertedWith( - "NOT_IMPLEMENTED" - ); - }); - }); - - describe("getReferenceData", async () => { - it("should fail if called with non saved _base", async () => { - await priceOracle.relay(["EEUR"], [42], [43]); - await expect(priceOracle.getReferenceData("FAIL", "EEUR")).revertedWith( - "REF_DATA_NOT_AVAILABLE" - ); - }); - - it("should fail if called with non saved _quote", async () => { - await priceOracle.relay(["EEUR"], [42], [43]); - await expect(priceOracle.getReferenceData("EEUR", "FAIL")).revertedWith( - "REF_DATA_NOT_AVAILABLE" - ); - }); - - it("should return ratio in reference data", async () => { - const eeurUsd = parseEther("0.975286"); - const eurUsd = parseEther("1.032572"); - await priceOracle.relay(["EEUR", "EUR"], [eeurUsd, eurUsd], [43, 44]); - - const result = await priceOracle.getReferenceData("EEUR", "EUR"); - - expect(result[0]).equal(BigNumber.from("944521060032617580")); - expect(result[1]).equal(43); - expect(result[2]).equal(44); - }); - - it("should return same when _quote is USD", async () => { - const eeurUsd = parseEther("0.975286"); - await priceOracle.relay(["EEUR"], [eeurUsd], [43]); - - const result = await priceOracle.getReferenceData("EEUR", "USD"); - - expect(result[0]).equal(BigNumber.from("975286000000000000")); - }); - - it("should return 1 / _quote when _base is USD", async () => { - const eeurUsd = parseEther("0.975286"); - await priceOracle.relay(["EEUR"], [eeurUsd], [43]); - - const result = await priceOracle.getReferenceData("USD", "EEUR"); - - expect(result[0]).equal(BigNumber.from("1025340259165003906")); - }); - }); -}); diff --git a/test/ResolutionManager.ts b/test/ResolutionManager.ts index 54a4ba3..58a08be 100644 --- a/test/ResolutionManager.ts +++ b/test/ResolutionManager.ts @@ -35,6 +35,8 @@ describe("Resolution", async () => { let resolutionSnapshotId = 42; let managingBoardStatus: string; + let investorStatus: string; + let contributorStatus: string; let daoRoles: MockContract; let voting: FakeContract; let token: FakeContract; @@ -78,6 +80,8 @@ describe("Resolution", async () => { await resolutionExecutorMock.deployed(); managingBoardStatus = await shareholderRegistry.MANAGING_BOARD_STATUS(); + investorStatus = await shareholderRegistry.INVESTOR_STATUS(); + contributorStatus = await shareholderRegistry.CONTRIBUTOR_STATUS(); resolution = (await upgrades.deployProxy( ResolutionFactory, @@ -1751,9 +1755,8 @@ describe("Resolution", async () => { }); }); - describe("addressable resolution", async () => { - let totalVotingPower = 100; - async function _prepare() { + describe("resolution with exclusion", async () => { + async function _prepare(totalVotingPower = 100) { await resolution .connect(managingBoard) .createResolutionWithExclusion("test", 6, [], [], user2.address); @@ -1779,20 +1782,28 @@ describe("Resolution", async () => { expect(voting.delegateFrom).not.called; }); - it("should remove and re-add delegation when delegating", async () => { + it("should downgrade the contributor to investor and, if delegating, restore status and delegation", async () => { await resolution .connect(managingBoard) .createResolutionWithExclusion("test", 0, [], [], user2.address); voting.getDelegate.whenCalledWith(user2.address).returns(user1.address); + shareholderRegistry.getStatus + .whenCalledWith(user2.address) + .returns(contributorStatus); await resolution.connect(managingBoard).approveResolution(resolutionId); - expect(voting.delegateFrom.getCall(0).args).deep.equal([ + expect(shareholderRegistry.setStatus.getCall(0).args).deep.equal([ + investorStatus, user2.address, + ]); + + expect(shareholderRegistry.setStatus.getCall(1).args).deep.equal([ + contributorStatus, user2.address, ]); - expect(voting.delegateFrom.getCall(1).args).deep.equal([ + expect(voting.delegateFrom.getCall(0).args).deep.equal([ user2.address, user1.address, ]); @@ -1807,87 +1818,6 @@ describe("Resolution", async () => { ).revertedWith("Resolution: account cannot vote"); }); - it("should not count excluded contributor balance for quorum", async () => { - setupUser(user2, 42, 60); - setupUser(user1, 42, 40); - await _prepare(); - - await resolution.connect(user1).vote(resolutionId, true); - - const result = await resolution.getResolutionResult(resolutionId); - - expect(result).to.be.true; - }); - - it("should not count excluded contributor shares for quorum", async () => { - setupUser(user2, 42, 0); - setupUser(user1, 42, 40); - shareholderRegistry.balanceOfAt - .whenCalledWith(user2.address, resolutionSnapshotId) - .returns(60); - await _prepare(); - - await resolution.connect(user1).vote(resolutionId, true); - - const result = await resolution.getResolutionResult(resolutionId); - - expect(result).to.be.true; - }); - - it("should count excluded contributor delegated's balance for quorum", async () => { - setupUser(user2, 42, 60, user1); - setupUser(user1, 42, 40); - await _prepare(); - - await resolution.connect(user1).vote(resolutionId, true); - - const result = await resolution.getResolutionResult(resolutionId); - - expect(result).to.be.true; - }); - - it("should count excluded contributor delegated's shares for quorum", async () => { - setupUser(user2, 42, 60, user1); - setupUser(user1, 42, 0); - shareholderRegistry.balanceOfAt - .whenCalledWith(user1.address, resolutionSnapshotId) - .returns(40); - await _prepare(); - - await resolution.connect(user1).vote(resolutionId, true); - - const result = await resolution.getResolutionResult(resolutionId); - - expect(result).to.be.true; - }); - - it("should count excluded contributor delegator's balance for quorum", async () => { - setupUser(user2, 42, 60); - setupUser(user1, 42, 40, user2); - await _prepare(); - - await resolution.connect(user1).vote(resolutionId, true); - - const result = await resolution.getResolutionResult(resolutionId); - - expect(result).to.be.true; - }); - - it("should count excluded contributor delegator's shares for quorum", async () => { - setupUser(user2, 42, 60); - setupUser(user1, 42, 0, user2); - shareholderRegistry.balanceOfAt - .whenCalledWith(user1.address, resolutionSnapshotId) - .returns(40); - await _prepare(); - - await resolution.connect(user1).vote(resolutionId, true); - - const result = await resolution.getResolutionResult(resolutionId); - - expect(result).to.be.true; - }); - describe("getVoterVote", async () => { it("should fail when asking stats for a user who is excluded", async () => { setupUser(user2, 42, 60);